Better support for variadic functions
This commit is contained in:
@@ -9,7 +9,7 @@ endif
|
|||||||
|
|
||||||
all: cweb.c cweb.h cozisnews$(EXT)
|
all: cweb.c cweb.h cozisnews$(EXT)
|
||||||
|
|
||||||
cweb.c cweb.h:
|
cweb.c cweb.h: src/main.c src/main.h
|
||||||
python amalg.py
|
python amalg.py
|
||||||
|
|
||||||
sqlite3.o: demo/sqlite3.c
|
sqlite3.o: demo/sqlite3.c
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Amalgamator:
|
|||||||
self.out += "// " + file + "\n"
|
self.out += "// " + file + "\n"
|
||||||
self.out += "////////////////////////////////////////////////////////////////////////////////////////\n"
|
self.out += "////////////////////////////////////////////////////////////////////////////////////////\n"
|
||||||
self.out += "\n"
|
self.out += "\n"
|
||||||
self.out += "#line 1 \"" + file + "\"\n"
|
#self.out += "#line 1 \"" + file + "\"\n"
|
||||||
self.out += open(file).read()
|
self.out += open(file).read()
|
||||||
|
|
||||||
if len(self.out) > 0 and self.out[len(self.out)-1] != '\n':
|
if len(self.out) > 0 and self.out[len(self.out)-1] != '\n':
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
// 3p/wl.h
|
// 3p/wl.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#line 1 "3p/wl.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@@ -101,7 +100,6 @@ void wl_append (WL_Runtime *rt);
|
|||||||
// 3p/chttp.h
|
// 3p/chttp.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#line 1 "3p/chttp.h"
|
|
||||||
#ifndef HTTP_AMALGAMATION
|
#ifndef HTTP_AMALGAMATION
|
||||||
#define HTTP_AMALGAMATION
|
#define HTTP_AMALGAMATION
|
||||||
|
|
||||||
@@ -633,7 +631,6 @@ int http_serve (char *addr, int port, HTTP_Router *router);
|
|||||||
// 3p/chttp.c
|
// 3p/chttp.c
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#line 1 "3p/chttp.c"
|
|
||||||
#ifndef HTTP_NOINCLUDE
|
#ifndef HTTP_NOINCLUDE
|
||||||
#include "chttp.h"
|
#include "chttp.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -6203,7 +6200,6 @@ int http_serve(char *addr, int port, HTTP_Router *router)
|
|||||||
// 3p/crypt_blowfish.h
|
// 3p/crypt_blowfish.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#line 1 "3p/crypt_blowfish.h"
|
|
||||||
/*
|
/*
|
||||||
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
||||||
* No copyright is claimed, and the software is hereby placed in the public
|
* No copyright is claimed, and the software is hereby placed in the public
|
||||||
@@ -6236,7 +6232,6 @@ extern char *_crypt_gensalt_blowfish_rn(const char *prefix,
|
|||||||
// 3p/crypt_blowfish.c
|
// 3p/crypt_blowfish.c
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#line 1 "3p/crypt_blowfish.c"
|
|
||||||
/*
|
/*
|
||||||
* The crypt_blowfish homepage is:
|
* The crypt_blowfish homepage is:
|
||||||
*
|
*
|
||||||
@@ -7149,7 +7144,6 @@ char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
|
|||||||
// 3p/wl.c
|
// 3p/wl.c
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#line 1 "3p/wl.c"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -12985,7 +12979,6 @@ void wl_runtime_dump(WL_Runtime *rt)
|
|||||||
// src/main.c
|
// src/main.c
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#line 1 "src/main.c"
|
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
#include "wl.h"
|
#include "wl.h"
|
||||||
#include "chttp.h"
|
#include "chttp.h"
|
||||||
@@ -13099,7 +13092,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_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_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_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_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_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 }; }
|
CWEB_VArg cweb_varg_from_pi (int *pi) { return (CWEB_VArg) { CWEB_VARG_TYPE_PI, .pi=pi }; }
|
||||||
@@ -13118,8 +13112,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_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_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_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
|
// RANDOM
|
||||||
@@ -13816,6 +13810,11 @@ CWEB_Request *cweb_wait(CWEB *cweb)
|
|||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str)
|
||||||
|
{
|
||||||
|
return http_streq(req->req->url.path, (HTTP_String) { str.ptr, str.len });
|
||||||
|
}
|
||||||
|
|
||||||
CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name)
|
CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name)
|
||||||
{
|
{
|
||||||
HTTP_String res = http_get_param(req->req->body,
|
HTTP_String res = http_get_param(req->req->body,
|
||||||
@@ -13859,12 +13858,155 @@ void cweb_respond(CWEB_Request *req, int status, CWEB_String content)
|
|||||||
http_response_builder_done(req->builder);
|
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 unused = out->cap - out->len;
|
||||||
int ret = snprintf(location, sizeof(location), "Location: %.*s", target.len, target.ptr);
|
if (unused > 0)
|
||||||
if (ret < 0 || ret >= SIZEOF(location)) {
|
memcpy(out->dst + out->len, src, MIN(len, unused));
|
||||||
// TODO
|
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);
|
http_response_builder_status(req->builder, 303);
|
||||||
@@ -13875,7 +14017,7 @@ void cweb_respond_redirect(CWEB_Request *req, CWEB_String target)
|
|||||||
http_response_builder_done(req->builder);
|
http_response_builder_done(req->builder);
|
||||||
return;
|
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);
|
http_response_builder_done(req->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
// src/main.h
|
// src/main.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#line 1 "src/main.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@@ -18,6 +17,10 @@ typedef struct {
|
|||||||
int len;
|
int len;
|
||||||
} CWEB_String;
|
} CWEB_String;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char data[61];
|
||||||
|
} CWEB_PasswordHash;
|
||||||
|
|
||||||
CWEB_String cweb_trim(CWEB_String s);
|
CWEB_String cweb_trim(CWEB_String s);
|
||||||
bool cweb_streq(CWEB_String a, CWEB_String b);
|
bool cweb_streq(CWEB_String a, CWEB_String b);
|
||||||
|
|
||||||
@@ -41,6 +44,7 @@ typedef enum {
|
|||||||
CWEB_VARG_TYPE_D,
|
CWEB_VARG_TYPE_D,
|
||||||
CWEB_VARG_TYPE_B,
|
CWEB_VARG_TYPE_B,
|
||||||
CWEB_VARG_TYPE_STR,
|
CWEB_VARG_TYPE_STR,
|
||||||
|
CWEB_VARG_TYPE_HASH,
|
||||||
CWEB_VARG_TYPE_PC,
|
CWEB_VARG_TYPE_PC,
|
||||||
CWEB_VARG_TYPE_PS,
|
CWEB_VARG_TYPE_PS,
|
||||||
CWEB_VARG_TYPE_PI,
|
CWEB_VARG_TYPE_PI,
|
||||||
@@ -60,6 +64,7 @@ typedef enum {
|
|||||||
CWEB_VARG_TYPE_PD,
|
CWEB_VARG_TYPE_PD,
|
||||||
CWEB_VARG_TYPE_PB,
|
CWEB_VARG_TYPE_PB,
|
||||||
CWEB_VARG_TYPE_PSTR,
|
CWEB_VARG_TYPE_PSTR,
|
||||||
|
CWEB_VARG_TYPE_PHASH,
|
||||||
} CWEB_VArgType;
|
} CWEB_VArgType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -84,6 +89,7 @@ typedef struct {
|
|||||||
double d;
|
double d;
|
||||||
bool b;
|
bool b;
|
||||||
CWEB_String str;
|
CWEB_String str;
|
||||||
|
CWEB_PasswordHash hash;
|
||||||
char *pc;
|
char *pc;
|
||||||
short *ps;
|
short *ps;
|
||||||
int *pi;
|
int *pi;
|
||||||
@@ -103,9 +109,15 @@ typedef struct {
|
|||||||
double *pd;
|
double *pd;
|
||||||
bool *pb;
|
bool *pb;
|
||||||
CWEB_String *pstr;
|
CWEB_String *pstr;
|
||||||
|
CWEB_PasswordHash *phash;
|
||||||
};
|
};
|
||||||
} CWEB_VArg;
|
} CWEB_VArg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int len;
|
||||||
|
CWEB_VArg *ptr;
|
||||||
|
} CWEB_VArgs;
|
||||||
|
|
||||||
CWEB_VArg cweb_varg_from_c (char c);
|
CWEB_VArg cweb_varg_from_c (char c);
|
||||||
CWEB_VArg cweb_varg_from_s (short s);
|
CWEB_VArg cweb_varg_from_s (short s);
|
||||||
CWEB_VArg cweb_varg_from_i (int i);
|
CWEB_VArg cweb_varg_from_i (int i);
|
||||||
@@ -125,6 +137,7 @@ CWEB_VArg cweb_varg_from_f (float f);
|
|||||||
CWEB_VArg cweb_varg_from_d (double d);
|
CWEB_VArg cweb_varg_from_d (double d);
|
||||||
CWEB_VArg cweb_varg_from_b (bool b);
|
CWEB_VArg cweb_varg_from_b (bool b);
|
||||||
CWEB_VArg cweb_varg_from_str (CWEB_String str);
|
CWEB_VArg cweb_varg_from_str (CWEB_String str);
|
||||||
|
CWEB_VArg cweb_varg_from_hash (CWEB_PasswordHash hash);
|
||||||
CWEB_VArg cweb_varg_from_pc (char *pc);
|
CWEB_VArg cweb_varg_from_pc (char *pc);
|
||||||
CWEB_VArg cweb_varg_from_ps (short *ps);
|
CWEB_VArg cweb_varg_from_ps (short *ps);
|
||||||
CWEB_VArg cweb_varg_from_pi (int *pi);
|
CWEB_VArg cweb_varg_from_pi (int *pi);
|
||||||
@@ -144,8 +157,9 @@ CWEB_VArg cweb_varg_from_pf (float *pf);
|
|||||||
CWEB_VArg cweb_varg_from_pd (double *pd);
|
CWEB_VArg cweb_varg_from_pd (double *pd);
|
||||||
CWEB_VArg cweb_varg_from_pb (bool *pb);
|
CWEB_VArg cweb_varg_from_pb (bool *pb);
|
||||||
CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr);
|
CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr);
|
||||||
|
CWEB_VArg cweb_varg_from_phash(CWEB_PasswordHash *phash);
|
||||||
|
|
||||||
#define CWEB_VARG(X) (_Generic((X), \
|
#define __CWEB_HELPER_ARG(X) (_Generic((X), \
|
||||||
char : cweb_varg_from_c, \
|
char : cweb_varg_from_c, \
|
||||||
short : cweb_varg_from_s, \
|
short : cweb_varg_from_s, \
|
||||||
int : cweb_varg_from_i, \
|
int : cweb_varg_from_i, \
|
||||||
@@ -165,6 +179,7 @@ CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr);
|
|||||||
double : cweb_varg_from_d, \
|
double : cweb_varg_from_d, \
|
||||||
bool : cweb_varg_from_b, \
|
bool : cweb_varg_from_b, \
|
||||||
CWEB_String : cweb_varg_from_str, \
|
CWEB_String : cweb_varg_from_str, \
|
||||||
|
CWEB_PasswordHash : cweb_varg_from_hash, \
|
||||||
char* : cweb_varg_from_pc, \
|
char* : cweb_varg_from_pc, \
|
||||||
short* : cweb_varg_from_ps, \
|
short* : cweb_varg_from_ps, \
|
||||||
int* : cweb_varg_from_pi, \
|
int* : cweb_varg_from_pi, \
|
||||||
@@ -183,21 +198,26 @@ CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr);
|
|||||||
float* : cweb_varg_from_pf, \
|
float* : cweb_varg_from_pf, \
|
||||||
double* : cweb_varg_from_pd, \
|
double* : cweb_varg_from_pd, \
|
||||||
bool* : cweb_varg_from_pb, \
|
bool* : cweb_varg_from_pb, \
|
||||||
CWEB_String* : cweb_varg_from_pstr \
|
CWEB_String* : cweb_varg_from_pstr, \
|
||||||
|
CWEB_PasswordHash* : cweb_varg_from_phash \
|
||||||
))(X)
|
))(X)
|
||||||
|
|
||||||
typedef struct {
|
// Helper macros
|
||||||
int len;
|
#define __CWEB_HELPER_DISPATCH_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
|
||||||
CWEB_VArg *ptr;
|
#define __CWEB_HELPER_CONCAT_0(A, B) A ## B
|
||||||
} CWEB_VArgs;
|
#define __CWEB_HELPER_CONCAT_1(A, B) __CWEB_HELPER_CONCAT_0(A, B)
|
||||||
|
#define __CWEB_HELPER_ARGS_0() (CWEB_VArgs) { 0, (CWEB_VArg[]) {}}
|
||||||
|
#define __CWEB_HELPER_ARGS_1(a) (CWEB_VArgs) { 1, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_2(a, b) (CWEB_VArgs) { 2, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_3(a, b, c) (CWEB_VArgs) { 3, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_4(a, b, c, d) (CWEB_VArgs) { 4, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_5(a, b, c, d, e) (CWEB_VArgs) { 5, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_6(a, b, c, d, e, f) (CWEB_VArgs) { 6, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e), __CWEB_HELPER_ARG(f) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_7(a, b, c, d, e, f, g) (CWEB_VArgs) { 7, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e), __CWEB_HELPER_ARG(f), __CWEB_HELPER_ARG(g) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_8(a, b, c, d, e, f, g, h) (CWEB_VArgs) { 8, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e), __CWEB_HELPER_ARG(f), __CWEB_HELPER_ARG(g), __CWEB_HELPER_ARG(h) }}
|
||||||
|
#define __CWEB_COUNT_ARGS(...) __CWEB_HELPER_DISPATCH_N(DUMMY, ##__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||||
|
|
||||||
#define CWEB_VARGS_1(a) (CWEB_VArgs) {1, (CWEB_VArg[]) { CWEB_VARG(a) } }
|
#define CWEB_VARGS(...) __CWEB_HELPER_CONCAT_1(__CWEB_HELPER_ARGS_, __CWEB_COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||||
#define CWEB_VARGS_2(a, b) (CWEB_VArgs) {2, (CWEB_VArg[]) { CWEB_VARG(a), CWEB_VARG(b) } }
|
|
||||||
#define CWEB_VARGS_3(a, b, c) (CWEB_VArgs) {3, (CWEB_VArg[]) { CWEB_VARG(a), CWEB_VARG(b), CWEB_VARG(c) } }
|
|
||||||
#define CWEB_VARGS_4(a, b, c, d) (CWEB_VArgs) {4, (CWEB_VArg[]) { CWEB_VARG(a), CWEB_VARG(b), CWEB_VARG(c), CWEB_VARG(d) } }
|
|
||||||
#define CWEB_VARGS_5(a, b, c, d, e) (CWEB_VArgs) {5, (CWEB_VArg[]) { CWEB_VARG(a), CWEB_VARG(b), CWEB_VARG(c), CWEB_VARG(d), CWEB_VARG(e) } }
|
|
||||||
#define CWEB_DISPATCH__(_1, _2, _3, _4, _5, NAME, ...) NAME
|
|
||||||
#define CWEB_VARGS(...) CWEB_DISPATCH__(__VA_ARGS__, CWEB_VARGS_5, CWEB_VARGS_4, CWEB_VARGS_3, CWEB_VARGS_2, CWEB_VARGS_1)(__VA_ARGS__)
|
|
||||||
|
|
||||||
typedef struct CWEB CWEB;
|
typedef struct CWEB CWEB;
|
||||||
typedef struct CWEB_Request CWEB_Request;
|
typedef struct CWEB_Request CWEB_Request;
|
||||||
@@ -222,6 +242,7 @@ int cweb_set_session_user_id(CWEB_Request *req, int user_id);
|
|||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
// Request
|
// Request
|
||||||
|
|
||||||
|
bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str);
|
||||||
CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name);
|
CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name);
|
||||||
int cweb_get_param_i(CWEB_Request *req, CWEB_String name);
|
int cweb_get_param_i(CWEB_Request *req, CWEB_String name);
|
||||||
|
|
||||||
@@ -229,9 +250,11 @@ int cweb_get_param_i(CWEB_Request *req, CWEB_String name);
|
|||||||
// Response
|
// Response
|
||||||
|
|
||||||
void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content);
|
void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content);
|
||||||
void cweb_respond_redirect(CWEB_Request *req, CWEB_String target);
|
void cweb_respond_redirect_impl(CWEB_Request *req, CWEB_String target_format, CWEB_VArgs args);
|
||||||
void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id);
|
void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id);
|
||||||
|
|
||||||
|
#define cweb_respond_redirect(req, format, ...) cweb_respond_redirect_impl((req), (format), CWEB_VARGS(__VA_ARGS__))
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
// Database
|
// Database
|
||||||
|
|
||||||
@@ -251,10 +274,6 @@ void cweb_free_query_result(CWEB_QueryResult *res);
|
|||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
// Password
|
// Password
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char data[61];
|
|
||||||
} CWEB_PasswordHash;
|
|
||||||
|
|
||||||
int cweb_hash_password(char *pass, int passlen, int cost, CWEB_PasswordHash *hash);
|
int cweb_hash_password(char *pass, int passlen, int cost, CWEB_PasswordHash *hash);
|
||||||
int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash);
|
int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash);
|
||||||
#endif // CWEB_AMALGAMATION
|
#endif // CWEB_AMALGAMATION
|
||||||
|
|||||||
+7
-7
@@ -125,7 +125,7 @@ static int user_exists(CWEB *cweb, CWEB_String name, CWEB_String pass)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = check_password(pass.ptr, pass.len, hash);
|
ret = cweb_check_password(pass.ptr, pass.len, hash);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
cweb_free_query_result(&res);
|
cweb_free_query_result(&res);
|
||||||
return -500;
|
return -500;
|
||||||
@@ -140,7 +140,7 @@ static int user_exists(CWEB *cweb, CWEB_String name, CWEB_String pass)
|
|||||||
|
|
||||||
static void endpoint_api_login(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_api_login(CWEB *cweb, CWEB_Request *req)
|
||||||
{
|
{
|
||||||
if (cweb_get_user_id(req) != -1) {
|
if (cweb_get_session_user_id(req) != -1) {
|
||||||
cweb_respond_redirect(req, CWEB_STR("/index"));
|
cweb_respond_redirect(req, CWEB_STR("/index"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ static void endpoint_api_login(CWEB *cweb, CWEB_Request *req)
|
|||||||
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid credentials</div>"));
|
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid credentials</div>"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cweb_set_user_id(req, ret) < 0) {
|
if (cweb_set_session_user_id(req, ret) < 0) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ static void endpoint_api_login(CWEB *cweb, CWEB_Request *req)
|
|||||||
|
|
||||||
static void endpoint_api_signup(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_api_signup(CWEB *cweb, CWEB_Request *req)
|
||||||
{
|
{
|
||||||
if (cweb_get_user_id(req) != -1) {
|
if (cweb_get_session_user_id(req) != -1) {
|
||||||
cweb_respond_redirect(req, CWEB_STR("/index"));
|
cweb_respond_redirect(req, CWEB_STR("/index"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ static void endpoint_api_signup(CWEB *cweb, CWEB_Request *req)
|
|||||||
cweb_respond_basic(req, 400, CWEB_STR("<div class=\"error\">Internal error</div>"));
|
cweb_respond_basic(req, 400, CWEB_STR("<div class=\"error\">Internal error</div>"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cweb_set_user_id(req, insert_id);
|
cweb_set_session_user_id(req, insert_id);
|
||||||
|
|
||||||
cweb_respond_redirect(req, CWEB_STR("/index"));
|
cweb_respond_redirect(req, CWEB_STR("/index"));
|
||||||
}
|
}
|
||||||
@@ -259,7 +259,7 @@ static void endpoint_api_post(CWEB *cweb, CWEB_Request *req)
|
|||||||
}
|
}
|
||||||
int post_id = (int) insert_id;
|
int post_id = (int) insert_id;
|
||||||
|
|
||||||
cweb_respond_redirect(req, "/post?id=%d", post_id);
|
cweb_respond_redirect(req, CWEB_STR("/post?id={}"), post_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req)
|
||||||
@@ -294,7 +294,7 @@ static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cweb_respond_redirect(req, "/post?id=%d", parent_post);
|
cweb_respond_redirect(req, CWEB_STR("/post?id={}"), parent_post);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void endpoint_index(CWEB *cweb, CWEB_Request *req)
|
static void endpoint_index(CWEB *cweb, CWEB_Request *req)
|
||||||
|
|||||||
+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_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_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_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_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_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 }; }
|
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_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_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_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
|
// RANDOM
|
||||||
@@ -876,12 +877,155 @@ void cweb_respond(CWEB_Request *req, int status, CWEB_String content)
|
|||||||
http_response_builder_done(req->builder);
|
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 unused = out->cap - out->len;
|
||||||
int ret = snprintf(location, sizeof(location), "Location: %.*s", target.len, target.ptr);
|
if (unused > 0)
|
||||||
if (ret < 0 || ret >= SIZEOF(location)) {
|
memcpy(out->dst + out->len, src, MIN(len, unused));
|
||||||
// TODO
|
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);
|
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);
|
http_response_builder_done(req->builder);
|
||||||
return;
|
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);
|
http_response_builder_done(req->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+37
-18
@@ -8,6 +8,10 @@ typedef struct {
|
|||||||
int len;
|
int len;
|
||||||
} CWEB_String;
|
} CWEB_String;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char data[61];
|
||||||
|
} CWEB_PasswordHash;
|
||||||
|
|
||||||
CWEB_String cweb_trim(CWEB_String s);
|
CWEB_String cweb_trim(CWEB_String s);
|
||||||
bool cweb_streq(CWEB_String a, CWEB_String b);
|
bool cweb_streq(CWEB_String a, CWEB_String b);
|
||||||
|
|
||||||
@@ -31,6 +35,7 @@ typedef enum {
|
|||||||
CWEB_VARG_TYPE_D,
|
CWEB_VARG_TYPE_D,
|
||||||
CWEB_VARG_TYPE_B,
|
CWEB_VARG_TYPE_B,
|
||||||
CWEB_VARG_TYPE_STR,
|
CWEB_VARG_TYPE_STR,
|
||||||
|
CWEB_VARG_TYPE_HASH,
|
||||||
CWEB_VARG_TYPE_PC,
|
CWEB_VARG_TYPE_PC,
|
||||||
CWEB_VARG_TYPE_PS,
|
CWEB_VARG_TYPE_PS,
|
||||||
CWEB_VARG_TYPE_PI,
|
CWEB_VARG_TYPE_PI,
|
||||||
@@ -50,6 +55,7 @@ typedef enum {
|
|||||||
CWEB_VARG_TYPE_PD,
|
CWEB_VARG_TYPE_PD,
|
||||||
CWEB_VARG_TYPE_PB,
|
CWEB_VARG_TYPE_PB,
|
||||||
CWEB_VARG_TYPE_PSTR,
|
CWEB_VARG_TYPE_PSTR,
|
||||||
|
CWEB_VARG_TYPE_PHASH,
|
||||||
} CWEB_VArgType;
|
} CWEB_VArgType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -74,6 +80,7 @@ typedef struct {
|
|||||||
double d;
|
double d;
|
||||||
bool b;
|
bool b;
|
||||||
CWEB_String str;
|
CWEB_String str;
|
||||||
|
CWEB_PasswordHash hash;
|
||||||
char *pc;
|
char *pc;
|
||||||
short *ps;
|
short *ps;
|
||||||
int *pi;
|
int *pi;
|
||||||
@@ -93,9 +100,15 @@ typedef struct {
|
|||||||
double *pd;
|
double *pd;
|
||||||
bool *pb;
|
bool *pb;
|
||||||
CWEB_String *pstr;
|
CWEB_String *pstr;
|
||||||
|
CWEB_PasswordHash *phash;
|
||||||
};
|
};
|
||||||
} CWEB_VArg;
|
} CWEB_VArg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int len;
|
||||||
|
CWEB_VArg *ptr;
|
||||||
|
} CWEB_VArgs;
|
||||||
|
|
||||||
CWEB_VArg cweb_varg_from_c (char c);
|
CWEB_VArg cweb_varg_from_c (char c);
|
||||||
CWEB_VArg cweb_varg_from_s (short s);
|
CWEB_VArg cweb_varg_from_s (short s);
|
||||||
CWEB_VArg cweb_varg_from_i (int i);
|
CWEB_VArg cweb_varg_from_i (int i);
|
||||||
@@ -115,6 +128,7 @@ CWEB_VArg cweb_varg_from_f (float f);
|
|||||||
CWEB_VArg cweb_varg_from_d (double d);
|
CWEB_VArg cweb_varg_from_d (double d);
|
||||||
CWEB_VArg cweb_varg_from_b (bool b);
|
CWEB_VArg cweb_varg_from_b (bool b);
|
||||||
CWEB_VArg cweb_varg_from_str (CWEB_String str);
|
CWEB_VArg cweb_varg_from_str (CWEB_String str);
|
||||||
|
CWEB_VArg cweb_varg_from_hash (CWEB_PasswordHash hash);
|
||||||
CWEB_VArg cweb_varg_from_pc (char *pc);
|
CWEB_VArg cweb_varg_from_pc (char *pc);
|
||||||
CWEB_VArg cweb_varg_from_ps (short *ps);
|
CWEB_VArg cweb_varg_from_ps (short *ps);
|
||||||
CWEB_VArg cweb_varg_from_pi (int *pi);
|
CWEB_VArg cweb_varg_from_pi (int *pi);
|
||||||
@@ -134,8 +148,9 @@ CWEB_VArg cweb_varg_from_pf (float *pf);
|
|||||||
CWEB_VArg cweb_varg_from_pd (double *pd);
|
CWEB_VArg cweb_varg_from_pd (double *pd);
|
||||||
CWEB_VArg cweb_varg_from_pb (bool *pb);
|
CWEB_VArg cweb_varg_from_pb (bool *pb);
|
||||||
CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr);
|
CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr);
|
||||||
|
CWEB_VArg cweb_varg_from_phash(CWEB_PasswordHash *phash);
|
||||||
|
|
||||||
#define CWEB_VARG(X) (_Generic((X), \
|
#define __CWEB_HELPER_ARG(X) (_Generic((X), \
|
||||||
char : cweb_varg_from_c, \
|
char : cweb_varg_from_c, \
|
||||||
short : cweb_varg_from_s, \
|
short : cweb_varg_from_s, \
|
||||||
int : cweb_varg_from_i, \
|
int : cweb_varg_from_i, \
|
||||||
@@ -155,6 +170,7 @@ CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr);
|
|||||||
double : cweb_varg_from_d, \
|
double : cweb_varg_from_d, \
|
||||||
bool : cweb_varg_from_b, \
|
bool : cweb_varg_from_b, \
|
||||||
CWEB_String : cweb_varg_from_str, \
|
CWEB_String : cweb_varg_from_str, \
|
||||||
|
CWEB_PasswordHash : cweb_varg_from_hash, \
|
||||||
char* : cweb_varg_from_pc, \
|
char* : cweb_varg_from_pc, \
|
||||||
short* : cweb_varg_from_ps, \
|
short* : cweb_varg_from_ps, \
|
||||||
int* : cweb_varg_from_pi, \
|
int* : cweb_varg_from_pi, \
|
||||||
@@ -173,21 +189,26 @@ CWEB_VArg cweb_varg_from_pstr (CWEB_String *pstr);
|
|||||||
float* : cweb_varg_from_pf, \
|
float* : cweb_varg_from_pf, \
|
||||||
double* : cweb_varg_from_pd, \
|
double* : cweb_varg_from_pd, \
|
||||||
bool* : cweb_varg_from_pb, \
|
bool* : cweb_varg_from_pb, \
|
||||||
CWEB_String* : cweb_varg_from_pstr \
|
CWEB_String* : cweb_varg_from_pstr, \
|
||||||
|
CWEB_PasswordHash* : cweb_varg_from_phash \
|
||||||
))(X)
|
))(X)
|
||||||
|
|
||||||
typedef struct {
|
// Helper macros
|
||||||
int len;
|
#define __CWEB_HELPER_DISPATCH_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
|
||||||
CWEB_VArg *ptr;
|
#define __CWEB_HELPER_CONCAT_0(A, B) A ## B
|
||||||
} CWEB_VArgs;
|
#define __CWEB_HELPER_CONCAT_1(A, B) __CWEB_HELPER_CONCAT_0(A, B)
|
||||||
|
#define __CWEB_HELPER_ARGS_0() (CWEB_VArgs) { 0, (CWEB_VArg[]) {}}
|
||||||
|
#define __CWEB_HELPER_ARGS_1(a) (CWEB_VArgs) { 1, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_2(a, b) (CWEB_VArgs) { 2, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_3(a, b, c) (CWEB_VArgs) { 3, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_4(a, b, c, d) (CWEB_VArgs) { 4, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_5(a, b, c, d, e) (CWEB_VArgs) { 5, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_6(a, b, c, d, e, f) (CWEB_VArgs) { 6, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e), __CWEB_HELPER_ARG(f) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_7(a, b, c, d, e, f, g) (CWEB_VArgs) { 7, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e), __CWEB_HELPER_ARG(f), __CWEB_HELPER_ARG(g) }}
|
||||||
|
#define __CWEB_HELPER_ARGS_8(a, b, c, d, e, f, g, h) (CWEB_VArgs) { 8, (CWEB_VArg[]) { __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e), __CWEB_HELPER_ARG(f), __CWEB_HELPER_ARG(g), __CWEB_HELPER_ARG(h) }}
|
||||||
|
#define __CWEB_COUNT_ARGS(...) __CWEB_HELPER_DISPATCH_N(DUMMY, ##__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||||
|
|
||||||
#define CWEB_VARGS_1(a) (CWEB_VArgs) {1, (CWEB_VArg[]) { CWEB_VARG(a) } }
|
#define CWEB_VARGS(...) __CWEB_HELPER_CONCAT_1(__CWEB_HELPER_ARGS_, __CWEB_COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||||
#define CWEB_VARGS_2(a, b) (CWEB_VArgs) {2, (CWEB_VArg[]) { CWEB_VARG(a), CWEB_VARG(b) } }
|
|
||||||
#define CWEB_VARGS_3(a, b, c) (CWEB_VArgs) {3, (CWEB_VArg[]) { CWEB_VARG(a), CWEB_VARG(b), CWEB_VARG(c) } }
|
|
||||||
#define CWEB_VARGS_4(a, b, c, d) (CWEB_VArgs) {4, (CWEB_VArg[]) { CWEB_VARG(a), CWEB_VARG(b), CWEB_VARG(c), CWEB_VARG(d) } }
|
|
||||||
#define CWEB_VARGS_5(a, b, c, d, e) (CWEB_VArgs) {5, (CWEB_VArg[]) { CWEB_VARG(a), CWEB_VARG(b), CWEB_VARG(c), CWEB_VARG(d), CWEB_VARG(e) } }
|
|
||||||
#define CWEB_DISPATCH__(_1, _2, _3, _4, _5, NAME, ...) NAME
|
|
||||||
#define CWEB_VARGS(...) CWEB_DISPATCH__(__VA_ARGS__, CWEB_VARGS_5, CWEB_VARGS_4, CWEB_VARGS_3, CWEB_VARGS_2, CWEB_VARGS_1)(__VA_ARGS__)
|
|
||||||
|
|
||||||
typedef struct CWEB CWEB;
|
typedef struct CWEB CWEB;
|
||||||
typedef struct CWEB_Request CWEB_Request;
|
typedef struct CWEB_Request CWEB_Request;
|
||||||
@@ -220,9 +241,11 @@ int cweb_get_param_i(CWEB_Request *req, CWEB_String name);
|
|||||||
// Response
|
// Response
|
||||||
|
|
||||||
void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content);
|
void cweb_respond_basic(CWEB_Request *req, int status, CWEB_String content);
|
||||||
void cweb_respond_redirect(CWEB_Request *req, CWEB_String target);
|
void cweb_respond_redirect_impl(CWEB_Request *req, CWEB_String target_format, CWEB_VArgs args);
|
||||||
void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id);
|
void cweb_respond_template(CWEB_Request *req, int status, CWEB_String template_file, int resource_id);
|
||||||
|
|
||||||
|
#define cweb_respond_redirect(req, format, ...) cweb_respond_redirect_impl((req), (format), CWEB_VARGS(__VA_ARGS__))
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
// Database
|
// Database
|
||||||
|
|
||||||
@@ -242,9 +265,5 @@ void cweb_free_query_result(CWEB_QueryResult *res);
|
|||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
// Password
|
// Password
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char data[61];
|
|
||||||
} CWEB_PasswordHash;
|
|
||||||
|
|
||||||
int cweb_hash_password(char *pass, int passlen, int cost, CWEB_PasswordHash *hash);
|
int cweb_hash_password(char *pass, int passlen, int cost, CWEB_PasswordHash *hash);
|
||||||
int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash);
|
int cweb_check_password(char *pass, int passlen, CWEB_PasswordHash hash);
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Helper macros
|
||||||
|
#define __CWEB_HELPER_DISPATCH_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
|
||||||
|
#define __CWEB_HELPER_CONCAT_0(A, B) A ## B
|
||||||
|
#define __CWEB_HELPER_CONCAT_1(A, B) __CWEB_HELPER_CONCAT_0(A, B)
|
||||||
|
#define __CWEB_HELPER_ARG(a) (a)
|
||||||
|
#define __CWEB_HELPER_ARGS_0() (CWEB_VArgs) { 0 }
|
||||||
|
#define __CWEB_HELPER_ARGS_1(a) (CWEB_VArgs) { 1, __CWEB_HELPER_ARG(a) }
|
||||||
|
#define __CWEB_HELPER_ARGS_2(a, b) (CWEB_VArgs) { 2, __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b) }
|
||||||
|
#define __CWEB_HELPER_ARGS_3(a, b, c) (CWEB_VArgs) { 3, __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c) }
|
||||||
|
#define __CWEB_HELPER_ARGS_4(a, b, c, d) (CWEB_VArgs) { 4, __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d) }
|
||||||
|
#define __CWEB_HELPER_ARGS_5(a, b, c, d, e) (CWEB_VArgs) { 5, __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e) }
|
||||||
|
#define __CWEB_HELPER_ARGS_6(a, b, c, d, e, f) (CWEB_VArgs) { 6, __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e), __CWEB_HELPER_ARG(f) }
|
||||||
|
#define __CWEB_HELPER_ARGS_7(a, b, c, d, e, f, g) (CWEB_VArgs) { 7, __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e), __CWEB_HELPER_ARG(f), __CWEB_HELPER_ARG(g) }
|
||||||
|
#define __CWEB_HELPER_ARGS_8(a, b, c, d, e, f, g, h) (CWEB_VArgs) { 8, __CWEB_HELPER_ARG(a), __CWEB_HELPER_ARG(b), __CWEB_HELPER_ARG(c), __CWEB_HELPER_ARG(d), __CWEB_HELPER_ARG(e), __CWEB_HELPER_ARG(f), __CWEB_HELPER_ARG(g), __CWEB_HELPER_ARG(h) }
|
||||||
|
#define __CWEB_COUNT_ARGS(...) __CWEB_HELPER_DISPATCH_N(DUMMY, ##__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||||
|
|
||||||
|
#define CWEB_ARGS(...) __CWEB_HELPER_CONCAT_1(__CWEB_HELPER_ARGS_, __CWEB_COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||||
|
|
||||||
|
CWEB_ARGS()
|
||||||
|
CWEB_ARGS(1)
|
||||||
|
CWEB_ARGS(1, 2)
|
||||||
|
CWEB_ARGS(1, 2, 3)
|
||||||
Reference in New Issue
Block a user