summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--.gitignore18
-rw-r--r--AUTHORS3
-rw-r--r--COPYING19
-rw-r--r--ChangeLog0
-rw-r--r--Makefile.am15
-rw-r--r--NEWS.xml6
-rw-r--r--NEWS.xsl24
-rw-r--r--README16
-rw-r--r--autogen.bash6
-rw-r--r--configure.ac23
-rw-r--r--src/.gitignore3
-rw-r--r--src/Makefile.am15
-rw-r--r--src/cliche.199
-rw-r--r--src/cliche.rl331
-rw-r--r--test/.gitignore22
-rw-r--r--test/Makefile.am32
-rw-r--r--test/r01_closing_at_the_line_start.clichec16
-rw-r--r--test/r01_closing_at_the_line_start.expected8
-rw-r--r--test/r02_anchor_after_literal.clichec8
-rw-r--r--test/r02_anchor_after_literal.expected3
-rw-r--r--test/r03_percent_after_empty.clichec8
-rw-r--r--test/r03_percent_after_empty.expected6
-rw-r--r--test/r04_too_seamless_transitions.clichec9
-rw-r--r--test/r04_too_seamless_transitions.expected3
24 files changed, 693 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8523ddd
--- a/dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
1/INSTALL
2Makefile
3Makefile.in
4/aclocal.m4
5/autom4te.cache/
6/config.h
7/config.h.in
8/config.log
9/config.status
10/configure
11/depcomp
12/install-sh
13/missing
14/stamp-h1
15.deps/
16/NEWS
17*.o
18*.cliche.cc
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a9fb0c7
--- a/dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
1Klever dissected:
2 Michael 'hacker' Krelin <hacker@klever.net>
3 Leonid Ivanov <kamel@klever.net>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..61a9dd2
--- a/dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
1Copyright (c) 2011 Klever Group (http://www.klever.net/)
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of
4this software and associated documentation files (the "Software"), to deal in
5the Software without restriction, including without limitation the rights to
6use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7of the Software, and to permit persons to whom the Software is furnished to do
8so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/ChangeLog
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..77e96ad
--- a/dev/null
+++ b/Makefile.am
@@ -0,0 +1,15 @@
1SUBDIRS=src test
2
3all-local: NEWS
4
5NEWS: NEWS.xsl NEWS.xml
6 $(XSLTPROC) -o $@ $^
7EXTRA_DIST = NEWS.xml NEWS.xsl
8
9ISSUEFILES = $$(find ${top_srcdir} -type f '(' \
10 -name '*.rl' -or -name '*.h' \
11 ')' ) \
12 ${top_srcdir}/configure.ac
13issues: todo fixme xxx
14todo fixme xxx:
15 @grep --color=auto -in '$@:' ${ISSUEFILES} || true
diff --git a/NEWS.xml b/NEWS.xml
new file mode 100644
index 0000000..106fbbd
--- a/dev/null
+++ b/NEWS.xml
@@ -0,0 +1,6 @@
1<?xml version="1.0" encoding="us-ascii"?>
2<news>
3 <version version="0.0" date="Aug 27th, 2011">
4 <ni>Initial release</ni>
5 </version>
6</news>
diff --git a/NEWS.xsl b/NEWS.xsl
new file mode 100644
index 0000000..7c71307
--- a/dev/null
+++ b/NEWS.xsl
@@ -0,0 +1,24 @@
1<?xml version="1.0" encoding="us-ascii"?>
2<xsl:stylesheet version="1.0"
3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
4 >
5 <xsl:output
6 method="text"
7 encoding="us-ascii"
8 media-type="text/plain" />
9
10 <xsl:template match="news">
11 <xsl:apply-templates/>
12 </xsl:template>
13 <xsl:template match="version">
14 <xsl:value-of select="concat(@version,' (',@date,')&#xA;')"/>
15 <xsl:apply-templates/>
16 </xsl:template>
17 <xsl:template match="ni">
18 <xsl:text> - </xsl:text>
19 <xsl:apply-templates mode="text"/>
20 <xsl:text>&#xA;</xsl:text>
21 </xsl:template>
22 <xsl:template match="*|text()"/>
23
24</xsl:stylesheet>
diff --git a/README b/README
new file mode 100644
index 0000000..fbaa062
--- a/dev/null
+++ b/README
@@ -0,0 +1,16 @@
1Constructs:
2
3code embedded in output:
4<%code> ++i; </%code>
5% ++i;
6
7output embedded in code:
8int i=0;
9<%output>whoa, it's <% i++ %>!</%output>
10
11embed literal in the code:
12#define URL "http://www.klever.net/"
13<%literal>
14 a text that is going to be there is a string
15 with some possibilities <% URL %>
16</%literal>
diff --git a/autogen.bash b/autogen.bash
new file mode 100644
index 0000000..14798fd
--- a/dev/null
+++ b/autogen.bash
@@ -0,0 +1,6 @@
1#!/bin/bash
2 aclocal \
3&& autoheader \
4&& automake -a \
5&& autoconf \
6&& ./configure "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..4ecdb31
--- a/dev/null
+++ b/configure.ac
@@ -0,0 +1,23 @@
1AC_INIT([cliche],[0.0],[cliche-bugs@klever.net])
2AC_CONFIG_SRCDIR([src/cliche.rl])
3AC_CONFIG_HEADERS([config.h])
4AM_INIT_AUTOMAKE([check-news dist-bzip2 parallel-tests color-tests])
5
6AC_PROG_INSTALL
7AC_PROG_CXX
8AC_PATH_PROG([RAGEL],[ragel],[false])
9test "$RAGEL" = "false" && AC_MSG_ERROR([No ragel FSM compiler found])
10AC_PROG_SED
11
12AC_PATH_PROG([XSLTPROC],[xsltproc],[true])
13
14AC_CHECK_FUNC([getopt_long],[
15 AC_DEFINE([HAVE_GETOPT_LONG],[1],[define to make use of getopt_long])
16])
17
18AC_CONFIG_FILES([
19 Makefile
20 src/Makefile
21 test/Makefile
22])
23AC_OUTPUT
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..090e0ca
--- a/dev/null
+++ b/src/.gitignore
@@ -0,0 +1,3 @@
1/COPYING.cc
2/cliche
3/cliche.cc
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..d5102a7
--- a/dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,15 @@
1bin_PROGRAMS = cliche
2man_MANS = cliche.1
3
4EXTRA_DIST=$(man_MANS)
5
6cliche_SOURCES = cliche.rl COPYING.cc
7CLEANFILES=cliche.cc
8
9COPYING.cc: ${top_srcdir}/COPYING
10 (echo 'const char *COPYING=' \
11 && $(SED) -e 's/"/\\"/g' -e 's/^/\"/' -e 's/$$/\\n\"/' \
12 && echo ';') <$< >$@ || (rm $@;exit 1)
13
14.rl.cc:
15 $(RAGEL) -C -o $@ $<
diff --git a/src/cliche.1 b/src/cliche.1
new file mode 100644
index 0000000..af61a15
--- a/dev/null
+++ b/src/cliche.1
@@ -0,0 +1,99 @@
1.TH cliche 1 "August 27th, 2011" "cliche" "Klever Group (http://www.klever.net/)"
2.hla en
3
4.SH NAME
5
6cliche \- A tinimalistc template preprocessor for c++
7
8.SH SYNOPSYS
9
10\fBcliche\fR
11[\fB-h\fR] [\fB--help\fR] [\fB--usage\fR]
12[\fB-V\fR] [\fB--version\fR]
13[\fB-L\fR] [\fB--license\fR]
14[\fB-o\fR \fIfile\fR] [\fB--output=\fR\fIfile\fR]
15[\fB-t\fR \fIcode\fR|\fIoutput\fR] [\fB--top=\fR\fIcode\fR|\fIoutput\fR]
16[\fB-C\fR] [\fB-O\fR]
17
18.SH DESCRIPTION
19
20cliche preprocesses its input to produce c++ code streaming
21out the template while executing embedded c++ code and
22expressions.
23
24An example of cliche input file may look like this:
25
26.ti 1
27#include <iostream>
28.ti 1
29int main() {
30.ti 2
31 for(int i=0;i<5;++i) {
32.ti 3
33 <%output>
34.ti 4
35 <i>Whoa, it's <b><% i %></b> already!</i><br/>
36.ti 3
37 </%output>
38.ti 2
39 }
40.ti 1
41}
42
43.SH OPTIONS
44
45.TP
46\fB-o\fR \fIfile\fR, \fB--output=\fR\fIfile\fR
47Write output to the specified file.
48.TP
49\fB-t\fR \fIcode\fR|\fIoutput\fR, \fB--top=\fR\fIcode\fR|\fIoutput\fR
50Expect input to have code or output (as if in <%code></%code> or <%output></%output> block) on the top-level. Code templates are suitable for feeding into compiler as is, whereas output templates may be better suited for #include.
51.TP
52\fB-C\fR
53Same as \fB-t code\fR.
54.TP
55\fB-O\fR
56Same as \fB-t output\fR.
57.TP
58\fB-h\fR, \fB--help\fR, \fB--usage\fR
59Display short usage instructions and exit.
60.TP
61\fB-V\fR, \fB--version\fR
62Report version and exit.
63.TP
64\fB-L\fR, \fB--license\fR
65Show licensing terms.
66
67.SH EXIT STATUS
68Unsurprisingly, \fBcliche\fR returns zero in case of success and non-zero otherwise.
69
70.SH AUTHOR
71
72Written by Michael Krelin <hacker@klever.net>
73
74
75.SH COPYRIGHT
76
77Copyright (c) 2011 Klever Group (http://www.klever.net/)
78
79Permission is hereby granted, free of charge, to any person obtaining a copy of
80this software and associated documentation files (the "Software"), to deal in
81the Software without restriction, including without limitation the rights to
82use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
83of the Software, and to permit persons to whom the Software is furnished to do
84so, subject to the following conditions:
85
86The above copyright notice and this permission notice shall be included in all
87copies or substantial portions of the Software.
88
89THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
91FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
92AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
94OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
95SOFTWARE.
96
97.SH BUGS
98
99You tell me. Send reports to <cliche-bugs@klever.net>
diff --git a/src/cliche.rl b/src/cliche.rl
new file mode 100644
index 0000000..1f1f07f
--- a/dev/null
+++ b/src/cliche.rl
@@ -0,0 +1,331 @@
1#include <getopt.h>
2#include <iostream>
3#include <cstring>
4#include <cassert>
5#include <algorithm>
6#include <fstream>
7
8#include "config.h"
9
10struct line_counting_monkey {
11 int n;
12 const char *p;
13 const char *fn;
14
15 line_counting_monkey(const char *fn_,const char *p_) : fn(fn_), n(1), p(p_) { }
16
17 int lineno(const char *pp) {
18 if(pp>p) {
19 n += std::count(p,pp,'\n');
20 p = pp;
21 }
22 return n;
23 }
24};
25
26struct code_writing_monkey {
27 std::ostream& o;
28 enum omode_type {
29 om_code = 0, om_output, om_inline, om_literal,
30 oms
31 };
32 omode_type omode;
33 int last_anchor, since_anchor;
34
35 code_writing_monkey(std::ostream& o_) : o(o_), omode(om_code), last_anchor(-1), since_anchor(0) { }
36
37 void modify(omode_type om,line_counting_monkey* lcm=0,const char *p=0) {
38 static const char *om_transitions[oms][oms] = {
39 // To: From:
40 // code output inline literal
41 { "", "CLICHE_OUTPUT_LITERAL(\n", "CLICHE_STREAM << (", "" }, // code
42 { ");\n", "", ");\n(CLICHE_STREAM) << (", 0 }, // output
43 { ");\n", ");\nCLICHE_OUTPUT_LITERAL(\n", "", 0 }, // inline
44 { " ", 0, 0, "" }, // literal
45 };
46 assert(0 <= omode && omode < oms);
47 assert(0 <= om && om < oms);
48 const char *t = om_transitions[omode][om];
49 assert(t); // TODO: complain?
50 o << t;
51 since_anchor += std::count(t,t+strlen(t),'\n');
52 if(lcm && t && *t && om!=omode && p) anchor(*lcm,p);
53 omode = om;
54 }
55
56 void prologue() {
57 assert(omode==om_code);
58 o <<
59 "#ifndef CLICHE_STREAM\n"
60 "# define CLICHE_STREAM (std::cout)\n"
61 "# define CLICHE_STREAM_AUTODEFINED\n"
62 "#endif\n"
63 "#ifndef CLICHE_OUTPUT_LITERAL\n"
64 "# define CLICHE_OUTPUT_LITERAL(sl) (CLICHE_STREAM).write((sl),sizeof(sl)-sizeof(\"\"))\n"
65 "#endif\n";
66 }
67 void epilogue() {
68 modify(om_code);
69 o << "\n"
70 "#ifdef CLICHE_STREAM_AUTODEFINED\n"
71 "# undef CLICHE_STREAM\n"
72 "# undef CLICHE_STREAM_AUTODEFINED\n"
73 "#endif\n";
74 }
75
76 void monkey(const char *d,size_t l=0) {
77 if(!(l || (l=strlen(d)))) return;
78 if(omode!=om_output && omode!=om_literal) {
79 since_anchor += std::count(d,d+l,'\n');
80 o.write(d,l);
81 return;
82 }
83 o.put('"');
84 const char *p=d;
85 while(l--) {
86 char c;
87 switch(*d) {
88 case '\r': c='r'; break;
89 case '\n': c='n'; break;
90 case '\t': c='t'; break;
91 case '\a': c='a'; break;
92 case '\b': c='b'; break;
93 case '\v': c='v'; break;
94 case '\f': c='f'; break;
95 case '\'': case '\"': case '\\': c=*d; break;
96 case 0: c='0'; break;
97 default: c=0; break;
98 };
99 if(!c) {
100 ++d;
101 continue;
102 }
103 if(p!=d) o.write(p,d-p);
104 o.put('\\');
105 if(c=='0')
106 o.write("000",3);
107 else
108 o.put(c);
109 p=++d;
110 }
111 if(p!=d) o.write(p,d-p);
112 o.write("\"\n",2); ++since_anchor;
113 }
114
115 void monkey_as(omode_type om,const char *d,size_t l=0,line_counting_monkey *lcm=0,const char *p=0) { modify(om,lcm,p); monkey(d,l); }
116
117 void anchor(line_counting_monkey& lcm,const char *p) {
118 // modify(om_code);
119 int l = lcm.lineno(p);
120 if(last_anchor>0 && last_anchor+since_anchor==l) return;
121 o << "\n#line " << (since_anchor=0,last_anchor=l) << " \"" << lcm.fn << "\"\n";
122 }
123};
124
125
126%%{
127 machine cliche;
128
129 linebreak = /[\r\n]/;
130
131 action monkey {
132 cwm.monkey(ts,te-ts);
133 }
134 action monkey_code {
135 cwm.monkey_as(cwm.om_code,ts,te-ts,&lcm,p);
136 }
137 action monkey_output {
138 cwm.monkey_as(cwm.om_output,ts,te-ts,&lcm,p);
139 }
140 action monkey_literal {
141 cwm.monkey_as(cwm.om_literal,ts,te-ts,&lcm,p);
142 }
143
144 slashstar_comment :=
145 ( any* :>> '*/' ) ${ cwm.monkey(fpc,1); } @{ fret; };
146
147 outputblock := |*
148 '%' (^linebreak)* linebreak { cwm.monkey_as(cwm.om_code,ts+1,te-ts-1,&lcm,p); };
149 any=> { fhold; fcall outputline; };
150
151 *|;
152 outputline := |*
153 (^linebreak)* linebreak -- ('</%output>' | '<%code>' | ('<%' space) ) { cwm.monkey_as(cwm.om_output,ts,te-ts,&lcm,p); fret; };
154 '<%code>' { cwm.modify(cwm.om_code,&lcm,p); fcall codeblock; };
155 '</%output>' { --top; fret; };
156 '<%' space { cwm.modify(cwm.om_inline,&lcm,p); fcall inlineblock; };
157 (^linebreak)+ -- ( '%' | '<' ) => monkey_output;
158 any => monkey_output;
159 *|;
160
161 inlineblock := |*
162 space '%>' { cwm.modify(cwm.om_code,&lcm,p); fret; };
163 "'" ( [^'\\] | /\\./ )* "'" => monkey;
164 '"' ( [^"\\] | /\\./ )* '"' => monkey;
165 '/*' { cwm.monkey("/*",2); fcall slashstar_comment; };
166 '//' (^linebreak)* (linebreak) => monkey;
167 any => monkey;
168 *|;
169
170 literalblock := |*
171 any => { fhold; fcall literalline; };
172 *|;
173 literalline := |*
174 (^linebreak)* linebreak -- ('</%literal>' | ('<%' space) ) { cwm.monkey_as(cwm.om_literal,ts,te-ts,&lcm,p); fret; };
175 '</%literal>' { --top; fret; };
176 '<%' space { cwm.modify(cwm.om_code,&lcm,p); fcall inlineblock; };
177 (^linebreak)+ -- ( '%' | '<' ) => monkey_literal;
178 any => monkey_literal;
179 *|;
180
181 codeblock := |*
182 '<%output>'{ fcall outputblock; };
183 '<%literal>'{ fcall literalblock; };
184 '</%code>'{ fret; };
185 "'" ( [^'\\] | /\\./ )* "'" => monkey_code;
186 '"' ( [^"\\] | /\\./ )* '"' => monkey_code;
187 '/*' { cwm.monkey("/*",2); fcall slashstar_comment; };
188 '//' (^linebreak)* (linebreak) => monkey_code;
189 any => monkey_code;
190 *|;
191
192 main := any >{
193 fhold;
194 switch(topmode) {
195 case code_writing_monkey::om_output: fgoto outputblock;
196 case code_writing_monkey::om_code: fgoto codeblock;
197 default: ;/* TODO: WTD? */
198 };
199 };
200}%%
201
202%% write data;
203
204static const char *biname = 0;
205static void display_usage() {
206 std::cerr << PACKAGE " Version " VERSION "\n"
207 "Copyright (c) 2011 Klever Group\n"
208 "\n"
209 " " << biname << " [otpions] [input-file]\n"
210 "\n"
211#ifdef HAVE_GETOPT_LONG
212 " -h, --help\n"
213 " --usage display this text\n"
214 " -V, --version display version number\n"
215 " -L, --license show license\n"
216 " -o <file>, --output=<file> write output to the named file\n"
217 " -t code|output, --top=code|output\n"
218#else
219 " -h display this text\n"
220 " -V display version number\n"
221 " -L show license\n"
222 " -o <file> write output to the named file\n"
223 " -t code|output\n"
224#endif
225 " set toplevel processing mode [output]\n"
226 " -C same as -t=code\n"
227 " -O same as -t=output (default)\n"
228 "\n";
229}
230
231int main(int argc,char *argv[]) {
232 biname = *argv;
233 std::string ofile;
234 code_writing_monkey::omode_type topmode = code_writing_monkey::om_output;
235 while(true) {
236 static const char shopts[] = "hVLo:t:CO";
237#if HAVE_GETOPT_LONG
238 static struct option opts[] = {
239 { "help", no_argument, 0, 'h' },
240 { "usage", no_argument, 0, 'h' },
241 { "version", no_argument, 0, 'V' },
242 { "license", no_argument, 0, 'L' },
243 { "output", required_argument, 0, 'o' },
244 { "top", required_argument, 0, 't' },
245 { NULL, 0, 0, 0 }
246 };
247 int c = getopt_long(argc,argv,shopts,opts,NULL);
248#else
249 int c = getopt(argc,argv,shopts);
250#endif
251 if(c==-1) break;
252 switch(c) {
253 case 't':
254 if(!strcasecmp(optarg,"code")) {
255 topmode = code_writing_monkey::om_code;
256 break;
257 }else if(!strcasecmp(optarg,"output")) {
258 topmode = code_writing_monkey::om_output;
259 break;
260 }
261 std::cerr << "Unkown '" << optarg << "' mode" << std::endl;
262 case '?': /* unknown option */
263 case 'h': display_usage(); exit(0); break;
264 case 'V': std::cerr << VERSION << std::endl; exit(0); break;
265 case 'L':
266 extern const char *COPYING;
267 std::cerr << COPYING << std::endl;
268 exit(0); break;
269 case 'o': ofile = optarg; break;
270 case 'C': topmode = code_writing_monkey::om_code; break;
271 case 'O': topmode = code_writing_monkey::om_output; break;
272 default:
273 std::cerr << "Huh?" << std::endl;
274 exit(1); break;
275 }
276 }
277#undef LS
278 if((optind+1)!=argc) {
279 display_usage(); exit(1);
280 /* TODO: or use stdin if no parameter specified? */
281 }
282
283 std::string ifile = argv[optind];
284 if(ofile.empty()) ofile = ifile+".cc";
285 std::ifstream ist(ifile.c_str(),std::ios::in);
286 std::ofstream ost(ofile.c_str(),std::ios::out);
287 if(!ost) {
288 std::cerr << "failed to open '" << ofile << "' for writing" << std::endl;
289 exit(2);
290 }
291
292 int cs, act;
293 char *ts, *te;
294 int stack[128], top=0;
295 %% write init;
296 char input[512];
297 int have = 0;
298 char *eof = 0;
299 code_writing_monkey cwm(ost);
300 cwm.prologue();
301 line_counting_monkey lcm(ifile.c_str(),input);
302 cwm.anchor(lcm,0);
303 while(!eof) {
304 if(have==sizeof(input)) {
305 std::cerr << "No space to read in" << std::endl;
306 break;
307 }
308 char *p = input+have;
309 int lw = sizeof(input)-have;
310 int lp = ist.read(p,lw).gcount();
311 char *pe = p+lp;
312 eof = (lp==lw)?0:pe;
313 %%write exec;
314 if(cs==cliche_error) {
315 std::cerr << "cliche error" << std::endl;
316 break;
317 }
318 if(ts) {
319 lcm.lineno(ts);
320 te = ((char*)memmove(input,ts,have=pe-ts)) + (te-ts);
321 ts = input;
322 }else{
323 lcm.lineno(pe);
324 have = 0;
325 }
326 lcm.p = input;
327 }
328 cwm.epilogue();
329 return 0;
330}
331/* vim:set ft=ragel ts=8 sw=8 cin si ai: */
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..54191cb
--- a/dev/null
+++ b/test/.gitignore
@@ -0,0 +1,22 @@
1/test-suite.log
2
3/r01_closing_at_the_line_start
4/r01_closing_at_the_line_start.out
5/r01_closing_at_the_line_start.diff
6/r01_closing_at_the_line_start.check
7/r01_closing_at_the_line_start.log
8/r02_anchor_after_literal
9/r02_anchor_after_literal.out
10/r02_anchor_after_literal.diff
11/r02_anchor_after_literal.check
12/r02_anchor_after_literal.log
13/r03_percent_after_empty
14/r03_percent_after_empty.out
15/r03_percent_after_empty.diff
16/r03_percent_after_empty.check
17/r03_percent_after_empty.log
18/r04_too_seamless_transitions
19/r04_too_seamless_transitions.out
20/r04_too_seamless_transitions.diff
21/r04_too_seamless_transitions.check
22/r04_too_seamless_transitions.log
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..705278d
--- a/dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,32 @@
1TESTS=\
2 r01_closing_at_the_line_start.clichec \
3 r02_anchor_after_literal.clichec \
4 r03_percent_after_empty.clichec \
5 r04_too_seamless_transitions.clichec
6
7EXTRA_DIST=$(TESTS)
8CLEANFILES = $(basename $(TESTS)) \
9 $(foreach s,.out .diff,$(addsuffix $s,$(basename $(TESTS))))
10.INTERMEDIATE: $(CLEANFILES)
11
12TEST_EXTENSIONS=.clichec
13CLICHEC_LOG_COMPILER=test_clichec() { \
14 $(MAKE) "$$(basename $$1 .clichec)"{,.{out,diff,check}} ;\
15}; test_clichec
16
17gitignore: .gitignore
18.gitignore: Makefile
19 for t in ${TESTS} ; do for f in "$${t%.*}"{,.{out,diff,check,log}} ; do \
20 grep -q "^/$$f" .gitignore || echo "/$$f" >>.gitignore ;\
21 done done
22
23CLICHE=${top_builddir}/src/cliche
24SUFFIXES=.clichec .cc .out .diff .check
25.clichec.cc:
26 $(CLICHE) -C -o $@ $<
27%.out: %
28 ${builddir}/$< >$@
29%.diff: ${builddir}/%.out ${srcdir}/%.expected
30 @-diff -u "$*.expected" "$*.out" >"$@"
31%.check: %.diff
32 @test -s "$<" && { cat "$*.out";cp "$*.out" "$*.unexpected" ; exit 1 ; } || true
diff --git a/test/r01_closing_at_the_line_start.clichec b/test/r01_closing_at_the_line_start.clichec
new file mode 100644
index 0000000..11ebd8f
--- a/dev/null
+++ b/test/r01_closing_at_the_line_start.clichec
@@ -0,0 +1,16 @@
1#include <iostream>
2int main() {
3const char *t0 =
4<%literal>
5
6 test-literal
7
8</%literal>;
9std::cout << t0;
10
11<%output>
12
13 test-output
14
15</%output>
16}
diff --git a/test/r01_closing_at_the_line_start.expected b/test/r01_closing_at_the_line_start.expected
new file mode 100644
index 0000000..7854811
--- a/dev/null
+++ b/test/r01_closing_at_the_line_start.expected
@@ -0,0 +1,8 @@
1
2
3 test-literal
4
5
6
7 test-output
8
diff --git a/test/r02_anchor_after_literal.clichec b/test/r02_anchor_after_literal.clichec
new file mode 100644
index 0000000..c2049c0
--- a/dev/null
+++ b/test/r02_anchor_after_literal.clichec
@@ -0,0 +1,8 @@
1#include <iostream>
2int main() {
3const char *l3 = <%literal>line 3</%literal> ":"; int nl3 = __LINE__;
4std::cout << l3 << nl3 << std::endl;
5{<%output>line 5 (<% __LINE__ %>)</%output>}
6int l6 = __LINE__;
7std::cout << std::endl << "line 6: " << l6 << std::endl;
8};
diff --git a/test/r02_anchor_after_literal.expected b/test/r02_anchor_after_literal.expected
new file mode 100644
index 0000000..b53c949
--- a/dev/null
+++ b/test/r02_anchor_after_literal.expected
@@ -0,0 +1,3 @@
1line 3:3
2line 5 (5)
3line 6: 6
diff --git a/test/r03_percent_after_empty.clichec b/test/r03_percent_after_empty.clichec
new file mode 100644
index 0000000..62c82eb
--- a/dev/null
+++ b/test/r03_percent_after_empty.clichec
@@ -0,0 +1,8 @@
1#include <iostream>
2int main() {<%output>
3Test for broken handling of '^% ' line following the empty line.
4Like this:
5
6% std::cout << 1 << std::endl;
7
8</%output>}
diff --git a/test/r03_percent_after_empty.expected b/test/r03_percent_after_empty.expected
new file mode 100644
index 0000000..f2ee7b2
--- a/dev/null
+++ b/test/r03_percent_after_empty.expected
@@ -0,0 +1,6 @@
1
2Test for broken handling of '^% ' line following the empty line.
3Like this:
4
51
6
diff --git a/test/r04_too_seamless_transitions.clichec b/test/r04_too_seamless_transitions.clichec
new file mode 100644
index 0000000..c313013
--- a/dev/null
+++ b/test/r04_too_seamless_transitions.clichec
@@ -0,0 +1,9 @@
1#include <iostream>
2int main() {
3int a=1,b=2;
4<%output>
5The transition like this - <% a %><% b %> should not glue 'ab' in the source together.
6Really.
7</%output>
8}
9
diff --git a/test/r04_too_seamless_transitions.expected b/test/r04_too_seamless_transitions.expected
new file mode 100644
index 0000000..2ab4e9f
--- a/dev/null
+++ b/test/r04_too_seamless_transitions.expected
@@ -0,0 +1,3 @@
1
2The transition like this - 12 should not glue 'ab' in the source together.
3Really.