static void val_buffer_fields( value v, field f, void *_l ) { vlist2 *l = (vlist2*)_l; if( l->prev ) buffer_append_sub(l->b,", ",2); else { buffer_append_sub(l->b," ",1); l->prev = 1; } val_buffer(l->b,val_field_name(f)); buffer_append_sub(l->b," => ",4); val_buffer_rec(l->b,v,(vlist*)l); }
DEFINE_FUNC_1(webp_decode_argb, data_buffer_value) { if (!val_is_buffer(data_buffer_value)) { val_throw(alloc_string("webp_decode_argb: Expected to be a buffer")); return alloc_null(); } buffer data_buffer = val_to_buffer(data_buffer_value); int data_len = buffer_size(data_buffer); char *data_ptr = buffer_data(data_buffer); int webp_width = -1, webp_height = -1; char *webp_data_ptr = (char *)WebPDecodeARGB((const unsigned char *)data_ptr, data_len, &webp_width, &webp_height); int webp_data_len = webp_width * webp_height * 4; if (webp_data_ptr == NULL) { val_throw(alloc_string("webp_decode_argb: Invalid webp data")); return alloc_null(); } buffer webp_buffer = alloc_buffer_len(0); buffer_append_sub(webp_buffer, webp_data_ptr, webp_data_len); buffer_set_size(webp_buffer, webp_data_len); value array = alloc_array(3); val_array_set_i(array, 0, alloc_int(webp_width)); val_array_set_i(array, 1, alloc_int(webp_height)); val_array_set_i(array, 2, buffer_val(webp_buffer)); if (webp_data_ptr != NULL) free(webp_data_ptr); return array; }
value hx_zmq_getbytessockopt(value socket_handle_,value option_) { val_check_kind(socket_handle_, k_zmq_socket_handle); if (!val_is_int(option_)) { val_throw(alloc_int(EINVAL)); return alloc_null(); } int rc = 0; int err = 0; char optval [255]; size_t optvallen = 255; rc = zmq_getsockopt(val_data(socket_handle_),val_int(option_),&optval, &optvallen); err = zmq_errno(); if (rc != 0) { val_throw(alloc_int(err)); return alloc_int(0); } // Return data to Haxe // Create a return buffer byte array, by memcopying the message data, then discard the ZMQ message buffer b = alloc_buffer(NULL); buffer_append_sub(b,optval,optvallen); err = zmq_errno(); if (rc != 0) { val_throw(alloc_int(err)); return alloc_null(); } return buffer_val(b); }
static value init_path( const char *path ) { value l = val_null, tmp; char *p, *p2; char *allocated = NULL; #ifdef NEKO_WINDOWS char exe_path[MAX_PATH]; if( path == NULL ) { # ifdef NEKO_STANDALONE # define SELF_DLL NULL # else # define SELF_DLL "neko.dll" # endif if( GetModuleFileName(GetModuleHandle(SELF_DLL),exe_path,MAX_PATH) == 0 ) return val_null; p = strrchr(exe_path,'\\'); if( p == NULL ) return val_null; *p = 0; path = exe_path; } #else if( path == NULL ) { allocated = strdup("/usr/local/lib/neko:/usr/lib/neko:/usr/local/bin:/usr/bin"); path = allocated; } #endif while( true ) { // windows drive letter (same behavior expected on all os) if( *path && path[1] == ':' ) { p = strchr(path+2,':'); p2 = strchr(path+2,';'); } else { p = strchr(path,':'); p2 = strchr(path,';'); } if( p == NULL || (p2 != NULL && p2 < p) ) p = p2; if( p != NULL ) *p = 0; tmp = alloc_array(2); if( (p && p[-1] != '/' && p[-1] != '\\') || (!p && path[strlen(path)-1] != '/' && path[strlen(path)-1] != '\\') ) { buffer b = alloc_buffer(path); char c = '/'; buffer_append_sub(b,&c,1); val_array_ptr(tmp)[0] = buffer_to_string(b); } else val_array_ptr(tmp)[0] = alloc_string(path); val_array_ptr(tmp)[1] = l; l = tmp; if( p != NULL ) *p = (p == p2)?';':':'; else break; path = p+1; } if( allocated != NULL ) free(allocated); return l; }
value ImagePngData(value img) { ImageData _img = getImage(img); int size; void *ptr = gdImagePngPtr(imageImage(_img),&size); buffer ret = alloc_buffer(NULL); buffer_append_sub(ret,ptr,size); gdFree(ptr); return buffer_to_string(ret); }
value ImageJpegData(value img, value quality) { ImageData _img = getImage(img); int _quality = val_int(quality); int size; void *ptr = gdImageJpegPtr(imageImage(_img),&size,_quality); buffer ret = alloc_buffer(NULL); buffer_append_sub(ret,ptr,size); gdFree(ptr); return buffer_to_string(ret); }
/** buffer_add_sub : 'buffer -> s:string -> p:int -> l:int -> void <doc>Add [l] characters of the string [s] starting at position [p]. An error occurs if out of string bounds.</doc> **/ static value buffer_add_sub( value b, value v, value p, value l ) { val_check_kind(b,k_buffer); val_check(v,string); val_check(p,int); val_check(l,int); if( val_int(p) < 0 || val_int(l) < 0 ) neko_error(); if( val_strlen(v) < val_int(p) || val_strlen(v) < val_int(p) + val_int(l) ) neko_error(); buffer_append_sub( (buffer)val_data(b), val_string(v) + val_int(p) , val_int(l) ); return val_true; }
// Append value to buffer void val_buffer(buffer inBuffer,value inValue) { hx::Object *obj = (hx::Object *)inValue; if (obj) { buffer_append(inBuffer, obj->toString().__CStr()); } else { buffer_append_sub(inBuffer,"null",4); } }
/** regexp_replace_fun : 'regexp -> from:string -> f:('regexp -> any) -> string <doc>Perform a replacement of all matched substrings by calling [f] for every match</doc> **/ static value regexp_replace_fun( value o, value s, value f ) { val_check_kind(o,k_regexp); val_check(s,string); val_check_function(f,1); { pcredata *d = PCRE(o); buffer b = alloc_buffer(NULL); int pos = 0; int len = val_strlen(s); const char *str = val_string(s); d->str = s; while( pcre_exec(d->r,NULL,str,len,pos,0,d->matchs,d->nmatchs * 3) >= 0 ) { buffer_append_sub(b,str+pos,d->matchs[0] - pos); val_buffer(b,val_call1(f,o)); pos = d->matchs[1]; } d->str = alloc_null(); buffer_append_sub(b,str+pos,len-pos); return buffer_to_string(b); } }
static value do_replace( value o, value s, value s2, bool all ) { val_check_kind(o,k_regexp); val_check(s,string); val_check(s2,string); { pcredata *d = PCRE(o); buffer b = alloc_buffer(NULL); int pos = 0; int len = val_strlen(s); const char *str = val_string(s); const char *str2 = val_string(s2); int len2 = val_strlen(s2); while( pcre_exec(d->r,NULL,str,len,pos,0,d->matchs,d->nmatchs * 3) >= 0 ) { buffer_append_sub(b,str+pos,d->matchs[0] - pos); buffer_append_sub(b,str2,len2); pos = d->matchs[1]; if( !all ) break; } d->str = alloc_null(); buffer_append_sub(b,str+pos,len-pos); return buffer_to_string(b); } }
value __SSL_read(value ssl) { buffer b; char buf[256]; int len; //val_check_kind(o,k_socket); b = alloc_buffer(NULL); while (true) { len = SSL_read((SSL*) val_data(ssl), buf, 256); //if( len == SOCKET_ERROR ) // return block_error(); if (len == 0) break; buffer_append_sub(b, buf, len); } return buffer_to_string(b); }
static void xml_error( const char *xml, const char *p, int *line, const char *msg ) { buffer b = alloc_buffer("Xml parse error : "); int l = (int)strlen(p); int nchars = 30; buffer_append(b,msg); buffer_append(b," at line "); val_buffer(b,alloc_int(*line)); buffer_append(b," : "); if( p != xml ) buffer_append(b,"..."); buffer_append_sub(b,p,(l < nchars)?l:nchars); if( l > nchars ) buffer_append(b,"..."); if( l == 0 ) buffer_append(b,"<eof>"); bfailure(b); }
static value nme_microphone_poll (value outHaxeObj) { mutex->Lock(); if (outgoing_pos > 0) { buffer buf = alloc_buffer_len(0); buffer_append_sub(buf, outgoing, outgoing_len); outgoing_pos = 0; outgoing_len = 0; alloc_field(outHaxeObj, val_id("state"), alloc_int(state)); state = 0; mutex->Unlock(); return buffer_val(buf); } else { mutex->Unlock(); return alloc_null(); } }
/** put_env : var:string -> val:string -> void <doc>Set some environment variable value</doc> **/ static value put_env( value e, value v ) { #ifdef NEKO_WINDOWS buffer b; val_check(e,string); val_check(v,string); b = alloc_buffer(NULL); val_buffer(b,e); buffer_append_sub(b,"=",1); val_buffer(b,v); if( putenv(val_string(buffer_to_string(b))) != 0 ) neko_error(); #else val_check(e,string); val_check(v,string); if( setenv(val_string(e),val_string(v),1) != 0 ) neko_error(); #endif return val_true; }
/** socket_read : 'socket -> string <doc>Read the whole content of a the data available from a socket until the connection close. If the socket hasn't been close by the other side, the function might block. </doc> **/ static value socket_read( value o ) { buffer b; char buf[256]; int len; val_check_kind(o,k_socket); b = alloc_buffer(NULL); while( true ) { POSIX_LABEL(read_again); len = recv(val_sock(o),buf,256,MSG_NOSIGNAL); if( len == SOCKET_ERROR ) { HANDLE_EINTR(read_again); return block_error(); } if( len == 0 ) break; buffer_append_sub(b,buf,len); } return buffer_to_string(b); }
static value ssl_read( value ssl ) { int len, bufsize = 256; buffer b; unsigned char buf[256]; mbedtls_ssl_context *ctx; val_check_kind(ssl,k_ssl); ctx = val_ssl(ssl); b = alloc_buffer(NULL); while( true ) { POSIX_LABEL(read_again); len = mbedtls_ssl_read( ctx, buf, bufsize ); if( len == SOCKET_ERROR ) { HANDLE_EINTR(read_again); return block_error(); } if( len == 0 ) break; buffer_append_sub(b,(const char *)buf,len); } return buffer_to_string(b); }
/** put_env : var:string -> val:string -> void <doc>Set some environment variable value</doc> **/ static value put_env( value e, value v ) { #ifdef HX_WINRT // Do nothing return alloc_null(); #elif defined(NEKO_WINDOWS) val_check(e,string); val_check(v,string); buffer b = alloc_buffer(0); val_buffer(b,e); buffer_append_sub(b,"=",1); val_buffer(b,v); if( putenv(buffer_data(b)) != 0 ) return alloc_null(); #else val_check(e,string); val_check(v,string); if( setenv(val_string(e),val_string(v),1) != 0 ) return alloc_null(); #endif return alloc_bool(true); }
/** socket_read : 'socket -> string <doc>Read the whole content of a the data available from a socket until the connection close. If the socket hasn't been close by the other side, the function might block. </doc> **/ static value socket_read( value o ) { buffer b; char buf[256]; int len; SOCKET sock = val_sock(o); b = alloc_buffer(NULL); gc_enter_blocking(); while( true ) { POSIX_LABEL(read_again); len = recv(sock,buf,256,MSG_NOSIGNAL); if( len == SOCKET_ERROR ) { HANDLE_EINTR(read_again); return block_error(); } if( len == 0 ) break; gc_exit_blocking(); buffer_append_sub(b,buf,len); gc_enter_blocking(); } gc_exit_blocking(); return buffer_val(b); }
static void val_buffer_rec( buffer b, value v, vlist *stack ) { char buf[32]; int i, l; vlist *vtmp = stack; while( vtmp != NULL ) { if( vtmp->v == v ) { buffer_append_sub(b,"...",3); return; } vtmp = vtmp->next; } switch( val_type(v) ) { case VAL_INT: buffer_append_sub(b,buf,sprintf(buf,"%d",val_int(v))); break; case VAL_STRING: buffer_append_sub(b,val_string(v),val_strlen(v)); break; case VAL_FLOAT: buffer_append_sub(b,buf,sprintf(buf,FLOAT_FMT,val_float(v))); break; case VAL_NULL: buffer_append_sub(b,"null",4); break; case VAL_BOOL: if( val_bool(v) ) buffer_append_sub(b,"true",4); else buffer_append_sub(b,"false",5); break; case VAL_FUNCTION: buffer_append_sub(b,buf,sprintf(buf,"#function:%d",val_fun_nargs(v))); break; case VAL_OBJECT: { value s = val_field(v,id_string); if( s != val_null ) s = val_callEx(v,s,NULL,0,NULL); if( val_is_string(s) ) buffer_append_sub(b,val_string(s),val_strlen(s)); else { vlist2 vtmp; vtmp.v = v; vtmp.next = stack; vtmp.b = b; vtmp.prev = 0; buffer_append_sub(b,"{",1); val_iter_fields(v,val_buffer_fields,&vtmp); if( vtmp.prev ) buffer_append_sub(b," }",2); else buffer_append_sub(b,"}",1); } break; } case VAL_ARRAY: buffer_append_sub(b,"[",1); l = val_array_size(v); { vlist vtmp; vtmp.v = v; vtmp.next = stack; for(i=0;i<l;i++) { value vi = val_array_ptr(v)[i]; val_buffer_rec(b,vi,&vtmp); if( i != l - 1 ) buffer_append_sub(b,",",1); } } buffer_append_sub(b,"]",1); break; case VAL_INT32: buffer_append_sub(b,buf,sprintf(buf,"%d",val_int32(v))); break; case VAL_ABSTRACT: buffer_append_sub(b,"#abstract",9); break; default: buffer_append_sub(b,"#unknown",8); break; } }
EXTERN void buffer_append( buffer b, const char *s ) { if( s == NULL ) return; buffer_append_sub(b,s,strlen(s)); }
static int neko_handler_rec( request_rec *r ) { mcontext ctx; neko_vm *vm; const char *ctype; value exc = NULL; /* Seems to crash on Windows. And on Linux, we rarely have libGC 7.x installed anyway # if defined(APACHE_2_X) || defined(NEKO_WINDOWS) // we are using threads, so let's make sure that the current thread is registered neko_thread_register(true); # endif */ config.hits++; ctx.r = r; ctx.main = cache_find(r); ctx.post_data = val_null; ctx.headers_sent = false; ctx.content_type = alloc_string("text/html"); r->content_type = val_string(ctx.content_type); if( ap_setup_client_block(r,REQUEST_CHUNKED_ERROR) != 0 ) { send_headers(&ctx); apache_error(APLOG_WARNING,r,"ap_setup_client_block failed"); return OK; } ctype = ap_table_get(r->headers_in,"Content-Type"); if( (!ctype || strstr(ctype,"multipart/form-data") == NULL) && ap_should_client_block(r) ) { # define MAXLEN 1024 char buf[MAXLEN]; int len; int tlen = 0; buffer b = alloc_buffer(NULL); while( (len = ap_get_client_block(r,buf,MAXLEN)) > 0 ) { if( tlen < config.max_post_size ) buffer_append_sub(b,buf,len); tlen += len; } if( tlen >= config.max_post_size ) { send_headers(&ctx); apache_error(APLOG_WARNING,r,"Maximum POST data exceeded. Try using multipart encoding"); return OK; } ctx.post_data = buffer_to_string(b); } vm = neko_vm_alloc(NULL); if( config.use_stats ) neko_vm_set_stats(vm,neko_stats_measure,config.use_prim_stats?neko_stats_measure:NULL); neko_vm_set_custom(vm,k_mod_neko,&ctx); if( config.use_jit && !neko_vm_jit(vm,1) ) { send_headers(&ctx); apache_error(APLOG_WARNING,r,"JIT required by env. var but not enabled in NekoVM"); return OK; } neko_vm_redirect(vm,request_print,&ctx); neko_vm_select(vm); if( ctx.main != NULL ) { value old = ctx.main; if( config.use_stats ) neko_stats_measure(vm,r->filename,1); val_callEx(val_null,old,NULL,0,&exc); if( config.use_stats ) neko_stats_measure(vm,r->filename,0); if( old != ctx.main ) cache_module(r->filename,FTIME(r),ctx.main); } else { char *base_uri = request_base_uri(r); value mload = neko_default_loader(&base_uri,1); value args[] = { alloc_string(r->filename), mload }; char *p = strrchr(val_string(args[0]),'.'); if( p != NULL ) *p = 0; val_callEx(mload,val_field(mload,val_id("loadmodule")),args,2,&exc); if( ctx.main != NULL && config.use_cache ) cache_module(r->filename,FTIME(r),ctx.main); } if( exc != NULL ) { buffer b = alloc_buffer(NULL); value v; int i; const char *p, *start; value st = neko_exc_stack(vm); val_buffer(b,exc); config.exceptions++; ap_soft_timeout("Client Timeout",r); send_headers(&ctx); v = buffer_to_string(b); p = val_string(v); start = p; ap_rprintf(r,"Uncaught exception - "); while( *p ) { if( *p == '<' || *p == '>' ) { ap_rwrite(start,(int)(p - start),r); ap_rwrite((*p == '<')?"<":">",4, r); start = p + 1; } p++; } ap_rwrite(start,(int)(p - start),r); ap_rprintf(r,"<br/><br/>"); for(i=0;i<val_array_size(st);i++) { value s = val_array_ptr(st)[i]; if( val_is_null(s) ) ap_rprintf(r,"Called from a C function<br/>"); else if( val_is_string(s) ) { ap_rprintf(r,"Called from %s (no debug available)<br/>",val_string(s)); } else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) ) ap_rprintf(r,"Called from %s line %d<br/>",val_string(val_array_ptr(s)[0]),val_int(val_array_ptr(s)[1])); else { b = alloc_buffer(NULL); val_buffer(b,s); ap_rprintf(r,"Called from %s<br/>",val_string(buffer_to_string(b))); } } ap_kill_timeout(r); return OK; } send_headers(&ctx); return OK; }
/** * Receive data from socket * Based on code in https://github.com/zeromq/jzmq/blob/master/src/Socket.cpp */ value hx_zmq_rcv(value socket_handle_, value flags) { val_check_kind(socket_handle_, k_zmq_socket_handle); if (!val_is_null(flags) && !val_is_int(flags)) { val_throw(alloc_int(EINVAL)); return alloc_null(); } zmq_msg_t message; int rc = zmq_msg_init (&message); int err = zmq_errno(); if (rc != 0) { val_throw(alloc_int(err)); return alloc_null(); } gc_enter_blocking(); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) rc = zmq_recvmsg (val_data(socket_handle_), &message, val_int(flags)); #else rc = zmq_recv (val_data(socket_handle_), &message, val_int(flags)); #endif gc_exit_blocking(); err = zmq_errno(); if (rc == -1 && err == EAGAIN) { rc = zmq_msg_close (&message); err = zmq_errno(); if (rc != 0) { val_throw(alloc_int(err)); return alloc_null(); } return alloc_null(); } if (rc == -1) { rc = zmq_msg_close (&message); int err1 = zmq_errno(); if (rc != 0) { val_throw(alloc_int(err1)); return alloc_null(); } val_throw(alloc_int(err)); return alloc_null(); } // Return data to Haxe int sz = zmq_msg_size (&message); const char* pd = (char *)zmq_msg_data (&message); // Create a return buffer byte array, by memcopying the message data, then discard the ZMQ message buffer b = alloc_buffer(NULL); buffer_append_sub(b,pd,sz); rc = zmq_msg_close (&message); err = zmq_errno(); if (rc != 0) { val_throw(alloc_int(err)); return alloc_null(); } return buffer_val(b); }
void api_buffer_append_sub(buffer inBuffer,const char *inStr,int inLen) { buffer_append_sub(inBuffer,inStr,inLen); }
DEFINE_FUNC_5(webp_encode_argb, data_buffer_value, width_value, height_value, lossless_value, quality_factor_value) { int width = 0; int height = 0; float quality_factor = 100; int lossless = 1; int stride = 0; uint8_t* abgr = NULL; uint8_t* rgba = NULL; uint8_t* output = NULL; int output_size = 0; int pixels_size; int bytes_size; buffer data_buffer; if (val_is_int(width_value)) width = val_int(width_value); if (val_is_int(height_value)) height = val_int(height_value); if (val_is_bool(lossless_value)) lossless = val_bool(lossless_value); if (val_is_float(quality_factor_value)) quality_factor = val_float(quality_factor_value); stride = width * 4; pixels_size = width * height; bytes_size = pixels_size * 4; if (!val_is_buffer(data_buffer_value)) { val_throw(alloc_string("webp_encode_argb: Expected to be a buffer")); return alloc_null(); } data_buffer = val_to_buffer(data_buffer_value); if (bytes_size != buffer_size(data_buffer)) { val_throw(alloc_string("webp_encode_argb: Invalid buffer size")); return alloc_null(); } //if () abgr = (uint8_t *)buffer_data(data_buffer); rgba = (uint8_t *)malloc(bytes_size); uint8_t* _abgr = abgr; uint8_t* _rgba = rgba; int _pixels_size = pixels_size; while (_pixels_size-- > 0) { //_rgba[0] = _abgr[3]; _rgba[0] = _abgr[1]; _rgba[1] = _abgr[2]; _rgba[2] = _abgr[3]; _rgba[3] = _abgr[0]; _abgr += 4; _rgba += 4; } if (lossless) { output_size = WebPEncodeLosslessRGBA( rgba, //abgr, width, height, stride, &output ); } else { output_size = WebPEncodeRGBA( rgba, //abgr, width, height, stride, quality_factor, &output ); } printf("output_size: (%d, %d, %d) : %d\n", width, height, stride, output_size); buffer output_buffer = alloc_buffer_len(0); buffer_append_sub(output_buffer, (char *)output, output_size); buffer_set_size(output_buffer, output_size); if (output != NULL) free(output); if (rgba != NULL) free(rgba); return buffer_val(output_buffer); }
/** sprintf : fmt:string -> params:(any | array) -> string <doc> Format a string. If only one parameter is needed then it can be directly passed, either the parameters need to be stored in an array. The following formats are accepted (with corresponding types) : <ul> <li>[%s] : string</li> <li>[%d] [%x] [%X] : int</li> <li>[%c] : int in the 0..255 range</li> <li>[%b] : bool</li> <li>[%f] : float</li> </ul> </doc> **/ static value neko_sprintf( value fmt, value params ) { const char *last, *cur, *end; int count = 0; buffer b; val_check(fmt,string); b = alloc_buffer(0); last = val_string(fmt); cur = last; end = cur + val_strlen(fmt); while( cur != end ) { if( *cur == '%' ) { int width = 0, prec = 0, flags = 0; buffer_append_sub(b,last,cur - last); cur++; while( *cur >= '0' && *cur <= '9' ) { width = width * 10 + (*cur - '0'); cur++; } if( *cur == '.' ) { cur++; while( *cur >= '0' && *cur <= '9' ) { prec = prec * 10 + (*cur - '0'); cur++; } } if( *cur == '%' ) { buffer_append_sub(b,"%",1); cur++; } else { value param; if( count == 0 && !val_is_array(params) ) { // first ? param = params; count++; } else if( !val_is_array(params) || val_array_size(params) <= count ) return alloc_null(); else param = val_array_i(params,count++); switch( *cur ) { case 'c': { int c; char cc; val_check(param,int); c = val_int(param); if( c < 0 || c > 255 ) return alloc_null(); cc = (char)c; buffer_append_sub(b,&cc,1); } break; case 'x': flags |= HEX_SMALL; case 'X': flags |= HEX; case 'd': { char tmp[10]; int sign = 0; int size = 0; int tsize; int n; val_check(param,int); n = val_int(param); if( !(flags & HEX) && n < 0 ) { sign++; prec--; n = -n; } else if( n == 0 ) tmp[9-size++] = '0'; if( flags & HEX ) { unsigned int nn = (unsigned int)n; while( nn > 0 ) { int k = nn&15; if( k < 10 ) tmp[9-size++] = k + '0'; else tmp[9-size++] = (k - 10) + ((flags & HEX_SMALL)?'a':'A'); nn = nn >> 4; } } else { while( n > 0 ) { tmp[9-size++] = (n % 10) + '0'; n = n / 10; } } tsize = (size > prec)?size:prec + sign; while( width > tsize ) { width--; buffer_append_sub(b," ",1); } if( sign ) buffer_append_sub(b,"-",1); while( prec > size ) { prec--; buffer_append_sub(b,"0",1); } buffer_append_sub(b,tmp+10-size,size); } break; case 'f': { val_check(param,float); val_buffer(b,param); } break; case 's': { int size; int tsize; val_check(param,string); size = val_strlen(param); tsize = (size > prec)?size:prec; while( width > tsize ) { width--; buffer_append_sub(b," ",1); } while( prec > size ) { prec--; buffer_append_sub(b," ",1); } buffer_append_sub(b,val_string(param),size); } break; case 'b': { val_check(param,bool); buffer_append_sub(b,val_bool(param)?"true":"false",val_bool(param)?4:5); } break; default: return alloc_null(); break; } }
void api_buffer_append_char(buffer inBuffer,int inChar) { char buf[2] = { inChar, '\0' }; buffer_append_sub(inBuffer,buf,1); }