Better support for variadic functions
This commit is contained in:
+153
-9
@@ -111,7 +111,8 @@ CWEB_VArg cweb_varg_from_ull (long long ull) { return (CWEB_VArg) { CWEB_VA
|
||||
CWEB_VArg cweb_varg_from_f (float f) { return (CWEB_VArg) { CWEB_VARG_TYPE_F, .f=f }; }
|
||||
CWEB_VArg cweb_varg_from_d (double d) { return (CWEB_VArg) { CWEB_VARG_TYPE_D, .d=d }; }
|
||||
CWEB_VArg cweb_varg_from_b (bool b) { return (CWEB_VArg) { CWEB_VARG_TYPE_B, .b=b }; }
|
||||
CWEB_VArg cweb_varg_from_str (HTTP_String str) { return (CWEB_VArg) { CWEB_VARG_TYPE_STR, .str=str }; }
|
||||
CWEB_VArg cweb_varg_from_str (CWEB_String str) { return (CWEB_VArg) { CWEB_VARG_TYPE_STR, .str=str }; }
|
||||
CWEB_VArg cweb_varg_from_hash (CWEB_PasswordHash hash) { return (CWEB_VArg) { CWEB_VARG_TYPE_HASH, .hash=hash }; }
|
||||
CWEB_VArg cweb_varg_from_pc (char *pc) { return (CWEB_VArg) { CWEB_VARG_TYPE_PC, .pc=pc }; }
|
||||
CWEB_VArg cweb_varg_from_ps (short *ps) { return (CWEB_VArg) { CWEB_VARG_TYPE_PS, .ps=ps }; }
|
||||
CWEB_VArg cweb_varg_from_pi (int *pi) { return (CWEB_VArg) { CWEB_VARG_TYPE_PI, .pi=pi }; }
|
||||
@@ -130,8 +131,8 @@ CWEB_VArg cweb_varg_from_pull (long long *pull) { return (CWEB_VArg) { CWEB_VA
|
||||
CWEB_VArg cweb_varg_from_pf (float *pf) { return (CWEB_VArg) { CWEB_VARG_TYPE_PF, .pf=pf }; }
|
||||
CWEB_VArg cweb_varg_from_pd (double *pd) { return (CWEB_VArg) { CWEB_VARG_TYPE_PD, .pd=pd }; }
|
||||
CWEB_VArg cweb_varg_from_pb (bool *pb) { return (CWEB_VArg) { CWEB_VARG_TYPE_PB, .pb=pb }; }
|
||||
CWEB_VArg cweb_varg_from_pstr (HTTP_String *pstr) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSTR, .pstr=pstr }; }
|
||||
|
||||
CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr) { return (CWEB_VArg) { CWEB_VARG_TYPE_PSTR, .pstr=pstr }; }
|
||||
CWEB_VArg cweb_varg_from_phash(CWEB_PasswordHash *phash) { return (CWEB_VArg) { CWEB_VARG_TYPE_PHASH, .phash=phash }; }
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// RANDOM
|
||||
@@ -876,12 +877,155 @@ void cweb_respond(CWEB_Request *req, int status, CWEB_String content)
|
||||
http_response_builder_done(req->builder);
|
||||
}
|
||||
|
||||
void cweb_respond_redirect(CWEB_Request *req, CWEB_String target)
|
||||
typedef struct {
|
||||
char *dst;
|
||||
int cap;
|
||||
int len;
|
||||
} StaticOutputBuffer;
|
||||
|
||||
static void append_to_output(StaticOutputBuffer *out, char *src, int len)
|
||||
{
|
||||
char location[128];
|
||||
int ret = snprintf(location, sizeof(location), "Location: %.*s", target.len, target.ptr);
|
||||
if (ret < 0 || ret >= SIZEOF(location)) {
|
||||
// TODO
|
||||
int unused = out->cap - out->len;
|
||||
if (unused > 0)
|
||||
memcpy(out->dst + out->len, src, MIN(len, unused));
|
||||
out->len += len;
|
||||
}
|
||||
|
||||
static void append_to_output_u64(StaticOutputBuffer *out, uint64_t n)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void append_to_output_s64(StaticOutputBuffer *out, int64_t n)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void append_to_output_ptr(StaticOutputBuffer *out, void *p)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void value_to_output(StaticOutputBuffer *out, CWEB_VArg arg)
|
||||
{
|
||||
switch (arg.type) {
|
||||
case CWEB_VARG_TYPE_C : append_to_output(out, &arg.c, 1); break;
|
||||
case CWEB_VARG_TYPE_S : append_to_output_s64(out, arg.s); break;
|
||||
case CWEB_VARG_TYPE_I : append_to_output_s64(out, arg.i); break;
|
||||
case CWEB_VARG_TYPE_L : append_to_output_s64(out, arg.l); break;
|
||||
case CWEB_VARG_TYPE_LL : append_to_output_s64(out, arg.ll); break;
|
||||
case CWEB_VARG_TYPE_SC : append_to_output_s64(out, arg.sc); break;
|
||||
case CWEB_VARG_TYPE_SS : append_to_output_s64(out, arg.ss); break;
|
||||
case CWEB_VARG_TYPE_SI : append_to_output_s64(out, arg.si); break;
|
||||
case CWEB_VARG_TYPE_SL : append_to_output_s64(out, arg.sl); break;
|
||||
case CWEB_VARG_TYPE_SLL : append_to_output_s64(out, arg.sll); break;
|
||||
case CWEB_VARG_TYPE_UC : append_to_output_u64(out, arg.uc); break;
|
||||
case CWEB_VARG_TYPE_US : append_to_output_u64(out, arg.us); break;
|
||||
case CWEB_VARG_TYPE_UI : append_to_output_u64(out, arg.ui); break;
|
||||
case CWEB_VARG_TYPE_UL : append_to_output_u64(out, arg.ul); break;
|
||||
case CWEB_VARG_TYPE_ULL : append_to_output_u64(out, arg.ull); break;
|
||||
case CWEB_VARG_TYPE_F : append_to_output_f64(out, arg.f); break;
|
||||
case CWEB_VARG_TYPE_D : append_to_output_u64(out, arg.d); break;
|
||||
case CWEB_VARG_TYPE_B : append_to_output(out, arg.b ? "true" : "false", arg.b ? 4: 5);break;
|
||||
case CWEB_VARG_TYPE_STR : append_to_output(out, arg.str.ptr, arg.str.len); break;
|
||||
case CWEB_VARG_TYPE_HASH : append_to_output(out, arg.hash.data, strlen(arg.hash.data)); break;
|
||||
case CWEB_VARG_TYPE_PC : append_to_output_ptr(out, arg.pc); break;
|
||||
case CWEB_VARG_TYPE_PS : append_to_output_ptr(out, arg.ps); break;
|
||||
case CWEB_VARG_TYPE_PI : append_to_output_ptr(out, arg.pi); break;
|
||||
case CWEB_VARG_TYPE_PL : append_to_output_ptr(out, arg.pl); break;
|
||||
case CWEB_VARG_TYPE_PLL : append_to_output_ptr(out, arg.pll); break;
|
||||
case CWEB_VARG_TYPE_PSC : append_to_output_ptr(out, arg.psc); break;
|
||||
case CWEB_VARG_TYPE_PSS : append_to_output_ptr(out, arg.pss); break;
|
||||
case CWEB_VARG_TYPE_PSI : append_to_output_ptr(out, arg.psi); break;
|
||||
case CWEB_VARG_TYPE_PSL : append_to_output_ptr(out, arg.psl); break;
|
||||
case CWEB_VARG_TYPE_PSLL : append_to_output_ptr(out, arg.psll); break;
|
||||
case CWEB_VARG_TYPE_PUC : append_to_output_ptr(out, arg.puc); break;
|
||||
case CWEB_VARG_TYPE_PUS : append_to_output_ptr(out, arg.pus); break;
|
||||
case CWEB_VARG_TYPE_PUI : append_to_output_ptr(out, arg.pui); break;
|
||||
case CWEB_VARG_TYPE_PUL : append_to_output_ptr(out, arg.pul); break;
|
||||
case CWEB_VARG_TYPE_PULL : append_to_output_ptr(out, arg.pull); break;
|
||||
case CWEB_VARG_TYPE_PF : append_to_output_ptr(out, arg.pf); break;
|
||||
case CWEB_VARG_TYPE_PD : append_to_output_ptr(out, arg.pd); break;
|
||||
case CWEB_VARG_TYPE_PB : append_to_output_ptr(out, arg.pb); break;
|
||||
case CWEB_VARG_TYPE_PSTR : append_to_output_ptr(out, arg.pstr); break;
|
||||
case CWEB_VARG_TYPE_PHASH: append_to_output_ptr(out, arg.phash); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void evaluate_format(StaticOutputBuffer *out, CWEB_String format, CWEB_VArgs args)
|
||||
{
|
||||
char *src = format.ptr;
|
||||
int len = format.len;
|
||||
int cur = 0;
|
||||
int arg_idx = 0;
|
||||
|
||||
for (;;) {
|
||||
|
||||
int off = cur;
|
||||
while (cur < len && src[cur] != '{' && src[cur] != '\\')
|
||||
cur++;
|
||||
|
||||
if (cur > off)
|
||||
append_to_output(out, src + off, cur - off);
|
||||
|
||||
if (cur == len)
|
||||
break;
|
||||
cur++;
|
||||
|
||||
if (src[cur-1] == '{') {
|
||||
|
||||
while (cur < len && src[cur] != '}')
|
||||
cur++;
|
||||
|
||||
if (cur < len) {
|
||||
assert(src[cur] == '}');
|
||||
cur++;
|
||||
}
|
||||
|
||||
if (arg_idx < args.len) {
|
||||
value_to_output(out, args.ptr[arg_idx]);
|
||||
arg_idx++;
|
||||
}
|
||||
|
||||
} else {
|
||||
assert(src[cur-1] == '\\');
|
||||
if (cur < len) {
|
||||
append_to_output(out, &src[cur], 1);
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CWEB_String evaluate_format_for_request_impl(CWEB_Request *req, CWEB_String format, CWEB_VArgs args)
|
||||
{
|
||||
StaticOutputBuffer out = {
|
||||
.dst = req->arena.ptr + req->arena.cur,
|
||||
.cap = req->arena.len - req->arena.cur,
|
||||
.len = 0
|
||||
};
|
||||
evaluate_format(&out, format, args);
|
||||
if (out.len > req->arena.len - req->arena.cur)
|
||||
return (CWEB_String) { NULL, 0 };
|
||||
req->arena.cur += out.len;
|
||||
return (CWEB_String) { out.dst, out.len };
|
||||
}
|
||||
#define evaluate_format_for_request(req, format, ...) evaluate_format_for_request_impl((req), (format), CWEB_VARGS(__VA_ARGS__))
|
||||
|
||||
void cweb_respond_redirect_impl(CWEB_Request *req, CWEB_String target_format, CWEB_VArgs args)
|
||||
{
|
||||
CWEB_String target = evaluate_format_for_request_impl(req, target_format, args);
|
||||
if (target.len == 0) {
|
||||
http_response_builder_status(req->builder, 500);
|
||||
http_response_builder_done(req->builder);
|
||||
return;
|
||||
}
|
||||
|
||||
CWEB_String location_header = evaluate_format_for_request(req, CWEB_STR("Location: {}"), target);
|
||||
if (location_header.len == 0) {
|
||||
http_response_builder_status(req->builder, 500);
|
||||
http_response_builder_done(req->builder);
|
||||
return;
|
||||
}
|
||||
|
||||
http_response_builder_status(req->builder, 303);
|
||||
@@ -892,7 +1036,7 @@ void cweb_respond_redirect(CWEB_Request *req, CWEB_String target)
|
||||
http_response_builder_done(req->builder);
|
||||
return;
|
||||
}
|
||||
http_response_builder_header(req->builder, (HTTP_String) { location, ret });
|
||||
http_response_builder_header(req->builder, (HTTP_String) { location_header.ptr, location_header.len });
|
||||
http_response_builder_done(req->builder);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user