+/* Impl. for #expand. */
+static void cmpp_dx_f_expand(cmpp_dx *dx){
+ cmpp_d const * const d = dx->d;
+ assert(d);
+ if( !dx->args.arg0 ){
+ cmpp_dx_err_set(dx, CMPP_RC_MISUSE,
+ "#expand requires one or two arguments");
+ return;
+ }
+ cmpp_arg const * argKav = 0 /* {key -> value ...} */;
+ cmpp_arg const * argToB = 0 /* one of X or Y from: #expand X Y */;
+ cmpp_arg const * aLhs = 0;
+ cmpp_arg const * aRhs = 0;
+ cmpp_arg const * aErr = 0;
+ cmpp_args args = cmpp_args_empty /* need a clone b/c of recursion */;
+ cmpp_b * const osIn = cmpp_b_borrow(dx->pp);
+ int nChomp = 0 /* Strip nChomp newlines from result */;
+ int unChomp = 0 /* Add unChomp newlines to result */;
+ bool raw = false /* interpret block content as raw or
+ preprocessor-ready? */;
+ bool inSp = false /* started a local savepoint? */;
+ if( !osIn || cmpp_dx_args_clone(dx, &args) ) goto end;
+ for( cmpp_arg const * arg = args.arg0;
+ 0==dxppCode && arg && !aRhs;
+ arg = arg->next ){
+ //g_warn("arg=%s", arg->z);
+ aErr = arg;
+ switch( arg->ttype ){
+ case cmpp_TT_Word:
+ if( cmpp_arg_isflag(arg,"-chomp") ){
+ ++nChomp;
+ continue;
+ }
+ if( cmpp_arg_isflag(arg,"-unchomp") ){
+ ++unChomp;
+ continue;
+ }
+ if( cmpp_arg_isflag(arg,"-raw") ){
+ raw = true;
+ continue;
+ }
+ if( !aLhs ){
+ aLhs = arg;
+ continue;
+ }
+ goto unexpected_arg;
+ default:
+ assert( !aRhs );
+ if( aLhs ){
+ if( (aErr = arg->next) ){
+ assert( arg!=aLhs );
+ assert( !aRhs );
+ goto unexpected_arg;
+ }
+ aRhs = arg;
+ }else{
+ aLhs = arg;
+ }
+ continue;
+ }
+ }
+ if( !aLhs ){
+ cmpp_dx_err_set(dx, CMPP_RC_MISUSE, "Expecting one or two arguments.");
+ goto end;
+ }
+ if( aRhs ){
+ if( cmpp_TT_GroupSquiggly!=aRhs->ttype ){
+ aErr = aRhs;
+ goto unexpected_arg;
+ }
+ argKav = aRhs;
+ argToB = aLhs;
+ }else{
+ if( cmpp_TT_GroupSquiggly==aLhs->ttype ){
+ argKav = aLhs;
+ }else{
+ argToB = aLhs;
+ }
+ }
+ assert( argKav || argToB );
+ if( argToB ){
+ if( cmpp_arg_to_b(dx, argToB, osIn, cmpp_arg_to_b_F_BRACE_CALL) ){
+ goto end;
+ }
+ }
+ if( argKav ){
+ assert(!argKav->next);
+ if( (aErr = argKav->next) ){
+ goto unexpected_arg;
+ }
+ if( cmpp_sp_begin(dx->pp) ) goto end;
+ inSp = true;
+ if( cmpp_kav_each(dx, argKav->z, argKav->n,
+ cmpp_kav_each_f_define__group,
+ 0,
+ cmpp_kav_each_F_EXPAND_VAL
+ | cmpp_kav_each_F_CALL_VAL
+ | cmpp_kav_each_F_PARENS_EXPR) ){
+ goto end;
+ }
+ }
+ if( argToB && cmpp_TT_GroupSquiggly==argToB->ttype ){
+ cmpp_outputer xout = cmpp_outputer_b;
+ cmpp_outputer old = {0};
+ cmpp_b * const b = cmpp_b_borrow(dx->pp);
+ if( !(xout.state = b) ) goto end;
+ cmpp__outputer_swap(dx->pp, &xout, &old);
+ cmpp_process_string(dx->pp, "#expand buffer", osIn->z, osIn->n);
+ cmpp__outputer_swap(dx->pp, &old, &xout);
+ cmpp_b_swap(b, osIn);
+ cmpp_b_return(dx->pp, b);
+ if( dxppCode ) goto end;
+ }
+ if( !argToB ){
+ assert(!osIn->n);
+ if( cmpp_dx_is_call(dx) ){
+ cmpp_dx_err_set(dx, CMPP_RC_MISUSE,
+ "#expand.../#expand is not legal for [call].");
+ goto end;
+ }
+ if( cmpp_dx_consume_b(dx, osIn, &dx->d->closer, 1,
+ raw
+ ? cmpp_dx_consume_F_RAW
+ : cmpp_dx_consume_F_PROCESS_OTHER_D) ){
+ goto end;
+ }
+ }
+ while( nChomp-- && cmpp_b_chomp(osIn) ){}
+ while( unChomp-- && cmpp_b_append_ch(osIn, '\n') ){}
+ //MARKER(("Emitting %d bytes: %.*s\n", (int)osIn->n, (int)osIn->n, osIn->z));
+ cmpp_dx_out_expand(dx, NULL, osIn->z, osIn->n, cmpp_atpol_CURRENT);
+
+end:
+ if( inSp ){
+ cmpp_sp_rollback(dx->pp);
+ }
+ cmpp_b_return(dx->pp, osIn);
+ cmpp_args_cleanup(&args);
+ return;
+unexpected_arg:
+ assert( aErr );
+ cmpp_dx_err_set(dx, CMPP_RC_MISUSE, "Unexpected argument: %.*s",
+ (int)aErr->n, aErr->z);
+ goto end;
+}
+
+