tag. If
passed any arguments, each is assumed to be a CSS class name and is
applied to the DIV. This does _not_ emit the lcosing DIV
tag. Returns 0 on success.
*/
static int divOpener(cmpp_dx *dx){
cmpp_dx_out_raw(dx, "
args.arg0;
0==cmpp_dx_err_check(dx) && a;
a = a->next ){
if( 1==++nClass ){
cmpp_dx_out_raw(dx, " class='", 8);
}else{
cmpp_dx_out_raw(dx, " ", 1);
}
cmpp_dx_out_raw(dx, a->z, a->n);
}
return cmpp_dx_out_raw(dx, nClass ? "'>" : ">", 1 + !!nClass);
}
/**
Opens an HTML DIV tag, as per divOpener().
*/
static void cmpp_dx_f_divOpen(cmpp_dx *dx){
if( 0==divOpener(dx) ){
int * const nDiv = dx->d->impl.state;
assert( nDiv );
++*nDiv;
}
}
/**
Closes an HTML DIV tag which was opened by cmpp_dx_f_divOpen().
*/
static void cmpp_dx_f_divClose(cmpp_dx *dx){
int * const nDiv = dx->d->impl.state;
assert( nDiv );
if( *nDiv > 0 ){
--*nDiv;
}else{
char const * const zDelim = cmpp_dx_delim(dx);
cmpp_dx_err_set(
dx, CMPP_RC_MISUSE,
"%s/%s was used without an opening %s%s directive",
zDelim, dx->d->name.z, zDelim, dx->d->name.z
);
}
}
/**
Another HTML DIV-inspired wrapper which consumes a block of input
and wraps it in a DIV. This is functionally the same as the
divOpen/divClose examples but demonstrates how to slurp up the
content between the open/close directives from within the opening
directive's callback.
*/
static void cmpp_dx_f_divWrapper(cmpp_dx *dx){
if( divOpener(dx) ) return;
cmpp_b os = {0};
if( 0==cmpp_dx_consume_b(
dx, &os, &dx->d->closer, 1,
cmpp_dx_consume_F_PROCESS_OTHER_D
)
/* ^^^ says "read to the matching #/div" accounting for, and
processing, nested directives). The #/div closing tag is
identified by dx->d->closer. */
){
cmpp_b_chomp( &os );
/* Recall that most cmpp APIs become no-ops if dx->pp has an error
set, so we don't strictly need to error-check these calls: */
cmpp_dx_out_raw(dx, os.z, os.n);
cmpp_dx_out_raw(dx, "
\n", 7);
}
cmpp_b_clear(&os);
}
/**
A cmpp_d_autoload_f() impl for testing and demonstration
purposes.
*/
int cmpp_d_autoload_f_demos(cmpp *pp, char const *dname, void *state){
(void)state;
cmpp_api_init(pp);
#define M(NAME) (0==strcmp(NAME,dname))
#define MOC(NAME) (M(NAME) || M("/"NAME))
#define DREG0(SYMNAME, NAME, OPENER, OFLAGS, CLOSER, CFLAGS) \
cmpp_d_reg SYMNAME = { \
.name = NAME, \
.opener = { \
.f = OPENER, \
.flags = OFLAGS \
}, \
.closer = { \
.f = CLOSER, \
.flags = CFLAGS \
}, \
.dtor = 0, \
.state = 0 \
}
#define CHECK(NAME,CHECKCLOSER,OPENER,OFLAGS,CLOSER,CFLAGS) \
if( M(NAME) || (CHECKCLOSER && M("/"NAME)) ){ \
DREG0(reg,NAME,OPENER,OFLAGS,CLOSER,CFLAGS); \
return cmpp_d_register(pp, ®, NULL); \
} (void)0
CHECK("demo1", 0, cmpp_dx_f_demo1, cmpp_d_F_ARGS_LIST, 0, 0);
CHECK("demo-div-wrapper", 1, cmpp_dx_f_divWrapper,
cmpp_d_F_ARGS_LIST | cmpp_d_F_NO_CALL,
cmpp_dx_f_dangling_closer, 0);
if( MOC("demo-div") ){
cmpp_d_reg const r = {
.name = "demo-div",
.opener = {
.f = cmpp_dx_f_divOpen,
.flags = cmpp_d_F_ARGS_LIST | cmpp_d_F_NO_CALL
},
.closer = {
.f = cmpp_dx_f_divClose
},
.state = cmpp_malloc(sizeof(int)),
.dtor = cmpp_mfree
};
/* State for one of the custom directives. */;
int const rc = cmpp_d_register(pp, &r, NULL);
if( 0==rc ){
*((int*)r.state) = 0
/* else reg.state was freed by cmpp_d_register() */;
}
return rc;
}
#undef M
#undef MOC
#undef CHECK
#undef DREG0
return CMPP_RC_NO_DIRECTIVE;
}
int cmpp_module__demo_register(cmpp *pp){
cmpp_api_init(pp);
int rc;
#define X(D) \
rc = cmpp_d_autoload_f_demos(pp, D, NULL); \
if( rc && CMPP_RC_NO_DIRECTIVE!=rc ) goto end
X("demo1");
X("demo-div");
X("demo-div-wrapper");
#undef X
end:
return cmpp_err_get(pp, NULL);
}
CMPP_MODULE_REGISTER1(demo);
#endif /* include guard */