1 /*
2     ClearSilver-CS.xs - Represents the CSPARSE* class
3 
4     Copyright(c) 2010 Craftworks. All rights reserved.
5 
6     See lib/Text/ClearSilver.pm for details.
7 */
8 
9 #include "Text-ClearSilver.h"
10 
11 NEOERR*
tcs_output_to_sv(void * vsv,char * s)12 tcs_output_to_sv(void* vsv, char* s) {
13 
14     if(*s){
15         dTHX;
16         SV* const sv     = (SV*)vsv;
17         STRLEN const len = strlen(s);
18 
19         if((SvLEN(sv) - SvCUR(sv)) <= len) {
20             sv_grow(sv, SvLEN(sv) * 2 + len);
21         }
22 
23         sv_catpvn(sv, s, len);
24     }
25 
26     return STATUS_OK;
27 }
28 
29 NEOERR*
tcs_output_to_io(void * io,char * s)30 tcs_output_to_io(void* io, char* s) {
31     bool ok;
32 
33     if(*s){
34         dTHX;
35         ENTER;
36         SAVETMPS;
37 
38         ok = Perl_do_print(aTHX_ newSVpvn_flags(s, strlen(s), SVs_TEMP), (PerlIO*)io);
39 
40         FREETMPS;
41         LEAVE;
42     }
43     else {
44         ok = TRUE;
45     }
46 
47     return ok
48         ? STATUS_OK
49         : nerr_raise(NERR_IO, "Unable to output to the filehandle");
50 }
51 
52 
53 
54 #undef cs_parse_string
55 #define cs_parse_string(cs, str) tcs_parse_sv(aTHX_ cs, str)
56 
57 /*
58     NOTE: Methods which seem to return NEOERR* throw errors when they fail,
59           otherwise return undef.
60  */
61 
62 MODULE = Text::ClearSilver::CS    PACKAGE = Text::ClearSilver::CS   PREFIX = cs_
63 
64 PROTOTYPES: DISABLE
65 
66 void
cs_new(SV * klass,SV * hdf_src)67 cs_new(SV* klass, SV* hdf_src)
68 CODE:
69 {
70     SV* self;
71     CSPARSE* cs;
72     HDF*     hdf;
73     SV* hdf_sv;
74 
75     if(SvROK(klass)){
76         croak("%s->new must be called as a class method", C_CS);
77     }
78 
79     self = sv_newmortal();
80     if(sv_derived_from(hdf_src, C_HDF) && SvROK(hdf_src)) {
81         hdf    = INT2PTR(HDF*, SvUV(SvRV(hdf_src)) );
82         hdf_sv = hdf_src;
83     }
84     else {
85         hdf    = tcs_new_hdf(aTHX_ hdf_src);
86         hdf_sv = sv_newmortal();
87         sv_setref_pv(hdf_sv, C_HDF, hdf);
88     }
89 
90     CHECK_ERR( cs_init(&cs, hdf) );
91 
92     tcs_register_funcs(aTHX_ cs, NULL);
93 
94     sv_setref_pv(self, SvPV_nolen_const(klass), cs);
95 
96     /* CS has a hdf */
97     if(hdf_sv){
98         static MGVTBL text_clearsilver_vtbl;
99         sv_magicext(SvRV(self), hdf_sv, PERL_MAGIC_ext,
100             &text_clearsilver_vtbl, NULL, 0);
101     }
102     ST(0) = self;
103 }
104 
105 void
cs_DESTROY(Text::ClearSilver::CS cs)106 cs_DESTROY(Text::ClearSilver::CS cs)
107 
108 void
109 cs_render(Text::ClearSilver::CS cs, PerlIO* ofp = NULL)
110 CODE:
111 {
112     dXSTARG;
113     NEOERR* err;
114     if(ofp) {
115         sv_setiv(TARG, TRUE);
116         err = cs_render(cs, ofp, tcs_output_to_io);
117     }
118     else {
119         sv_setpvs(TARG, "");
120         err = cs_render(cs, TARG, tcs_output_to_sv);
121     }
122     CHECK_ERR(err);
123     ST(0) = TARG;
124     XSRETURN(1);
125 }
126 
127 NEOERR*
cs_parse_file(Text::ClearSilver::CS cs,const char * cs_file)128 cs_parse_file(Text::ClearSilver::CS cs, const char* cs_file)
129 
130 NEOERR*
131 cs_parse_string(Text::ClearSilver::CS cs, SV* in_str)
132 
133 void
134 cs_dump(Text::ClearSilver::CS cs)
135 CODE:
136 {
137     dXSTARG;
138     sv_setpvs(TARG, "");
139     cs_dump(cs, (void*)TARG, tcs_output_to_sv);
140     ST(0) = TARG;
141     XSRETURN(1);
142 }
143 
144