Skip to content

Instantly share code, notes, and snippets.

@LadyNamedLaura
Created September 4, 2012 17:07
Show Gist options
  • Save LadyNamedLaura/3623568 to your computer and use it in GitHub Desktop.
Save LadyNamedLaura/3623568 to your computer and use it in GitHub Desktop.
aasprintf: alloca based asprintf
#include <alloca.h>
#include <stdio.h>
#pragma once
/*
* (v)aasprintf macro:
* alloca based asprintf
*
* usage:
* char *aasprintf(int length, char* fmt, ...)
* char *vaasprintf(int length, char* fmt, va_list ap)
*
* length is the length of the buffer to initially allocate,
* if the resulting string is longer, a larger buffer wil get allocated.
*
* all arguments exept length and ap are side_effect safe.
*
* currently up to 10 parameters alowed, to extend this, extend __ARG_STORE_ELEMENTS_* and __ARG_GET_LIST_TO_*.
*/
#define aasprintf(length, ...) ({\
int __TMPVAR(len) = 0;\
char* __TMPVAR(buffer) = alloca(length);\
__ARG_STORE_ELEMENTS(ARGCOUNT(__VA_ARGS__),__VA_ARGS__)\
__TMPVAR(len) = snprintf(__TMPVAR(buffer), length, __ARG_GET_LIST_TO(ARGCOUNT(__VA_ARGS__))); \
if (__TMPVAR(len) >= length){\
__TMPVAR(buffer) = alloca(__TMPVAR(len)+1); \
__TMPVAR(len) = snprintf(__TMPVAR(buffer), __TMPVAR(len)+1, __ARG_GET_LIST_TO(ARGCOUNT(__VA_ARGS__))); \
}\
__TMPVAR(len)>=0?__TMPVAR(buffer): NULL; })
#define vaasprintf(length, fmt, ap) ({\
int __TMPVAR(len) = 0;\
char* __TMPVAR(buffer) = alloca(length), __TMPVAR(format) = (fmt);\
va_list __TMPVAR(arglist);\
va_copy(__TMPVAR(arglist),ap);\
__TMPVAR(len) = vsnprintf(__TMPVAR(buffer), length, __TMPVAR(format), __TMPVAR(arglist));\
va_end(__TMPVAR(arglist));\
if (__TMPVAR(len) >= length){\
__TMPVAR(buffer) = alloca(__TMPVAR(len)+1); \
va_copy(__TMPVAR(arglist),ap);\
__TMPVAR(len) = snprintf(__TMPVAR(buffer), __TMPVAR(len)+1, __TMPVAR(format), __TMPVAR(arglist)); \
va_end(__TMPVAR(arglist));\
}\
__TMPVAR(len)>=0?__TMPVAR(buffer): NULL; })
#define __cat(a,b) a ## b
#define cat(a,b) __cat(a,b)
#define __TMPVAR(id) cat(cat(__tmpvar_,id), cat(_line,__LINE__))
#define ARGCOUNT(...) __ARGCOUNT(__VA_ARGS__, 63,62,61,60,59,58,57,56,55,54,53,52,51,50,\
49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,\
25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
#define __ARGCOUNT(...) __GET_ARG64(__VA_ARGS__)
#define __GET_ARG64(_1, _2, _3, _4, _5, _6, _7, _8, _9,_10,\
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,\
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,\
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,\
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,\
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,\
_61,_62,_63,N,...) N
#define __ARG_STORE_ELEMENTS(max,...) cat(__ARG_STORE_ELEMENTS_,max)(__VA_ARGS__)
#define __ARG_GET_LIST_TO(max) cat(__ARG_GET_LIST_TO_,max)()
#define __ARG_STORE(arg, id) typeof(arg) __TMPVAR(cat(arglist_,id)) = (arg);
#define __ARG_STORE_ELEMENTS_1(N) __ARG_STORE(N, 1)
#define __ARG_STORE_ELEMENTS_2(N,...) __ARG_STORE(N,2) __ARG_STORE_ELEMENTS_1(__VA_ARGS__)
#define __ARG_STORE_ELEMENTS_3(N,...) __ARG_STORE(N,3) __ARG_STORE_ELEMENTS_2(__VA_ARGS__)
#define __ARG_STORE_ELEMENTS_4(N,...) __ARG_STORE(N,4) __ARG_STORE_ELEMENTS_3(__VA_ARGS__)
#define __ARG_STORE_ELEMENTS_5(N,...) __ARG_STORE(N,5) __ARG_STORE_ELEMENTS_4(__VA_ARGS__)
#define __ARG_STORE_ELEMENTS_6(N,...) __ARG_STORE(N,6) __ARG_STORE_ELEMENTS_5(__VA_ARGS__)
#define __ARG_STORE_ELEMENTS_7(N,...) __ARG_STORE(N,7) __ARG_STORE_ELEMENTS_6(__VA_ARGS__)
#define __ARG_STORE_ELEMENTS_8(N,...) __ARG_STORE(N,8) __ARG_STORE_ELEMENTS_7(__VA_ARGS__)
#define __ARG_STORE_ELEMENTS_9(N,...) __ARG_STORE(N,9) __ARG_STORE_ELEMENTS_8(__VA_ARGS__)
#define __ARG_STORE_ELEMENTS_10(N,...) __ARG_STORE(N,10) __ARG_STORE_ELEMENTS_9(__VA_ARGS__)
#define __ARG_STORE_ELEMENTS_11(N,...) __ARG_STORE(N,11) __ARG_STORE_ELEMENTS_10(__VA_ARGS__)
#define __ARG_GET_LIST_TO_1() __TMPVAR(arglist_1)
#define __ARG_GET_LIST_TO_2() __TMPVAR(arglist_2), __ARG_GET_LIST_TO_1()
#define __ARG_GET_LIST_TO_3() __TMPVAR(arglist_3), __ARG_GET_LIST_TO_2()
#define __ARG_GET_LIST_TO_4() __TMPVAR(arglist_4), __ARG_GET_LIST_TO_3()
#define __ARG_GET_LIST_TO_5() __TMPVAR(arglist_5), __ARG_GET_LIST_TO_4()
#define __ARG_GET_LIST_TO_6() __TMPVAR(arglist_6), __ARG_GET_LIST_TO_5()
#define __ARG_GET_LIST_TO_7() __TMPVAR(arglist_7), __ARG_GET_LIST_TO_6()
#define __ARG_GET_LIST_TO_8() __TMPVAR(arglist_8), __ARG_GET_LIST_TO_7()
#define __ARG_GET_LIST_TO_9() __TMPVAR(arglist_9), __ARG_GET_LIST_TO_8()
#define __ARG_GET_LIST_TO_10() __TMPVAR(arglist_10), __ARG_GET_LIST_TO_9()
#define __ARG_GET_LIST_TO_11() __TMPVAR(arglist_11), __ARG_GET_LIST_TO_10()
@LadyNamedLaura
Copy link
Author

just to explain how it works:

    char *string = aasprintf(32, "test %d",++j);

becomes:

    char *string = ({
            int len = 0;
            char* buffer = alloca(32);
            typeof("test %d") arglist_2 = ("test %d");
            typeof(++j) arglist_1 = (++j);
            len = snprintf(buffer, 32, arglist_2, arglist_1);
            if (len >= 32) {
                buffer = alloca(len + 1);
                len = snprintf(buffer, len + 1, arglist_2, arglist_1);
            }
            len >= 0 ? buffer: NULL; });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment