source: trunk/kitgen/g2lite.c

Last change on this file was 175, checked in by demin, 12 years ago

initial commit

File size: 6.8 KB
Line 
1
2/*
3 Copyright (c) 2007, Pavel Demin
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms,
8 with or without modification, are permitted
9 provided that the following conditions are met:
10
11 * Redistributions of source code must retain
12 the above copyright notice, this list of conditions
13 and the following disclaimer.
14 * Redistributions in binary form must reproduce
15 the above copyright notice, this list of conditions
16 and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
18 * Neither the name of the SRMlite nor the names of its
19 contributors may be used to endorse or promote products
20 derived from this software without specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
26 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33*/
34
35#include <tcl.h>
36
37#define G2_POS_MAX 512
38
39enum
40{
41 G2_MODE_S = 1,
42 G2_MODE_AT = 2,
43 G2_MODE_VAR = 4,
44 G2_MODE_COPY = 8,
45 G2_MODE_IGNORE_SPACES = 16
46};
47
48/* ----------------------------------------------------------------- */
49
50typedef struct
51{
52 int pos;
53 int level;
54 unsigned char mode;
55 Tcl_UniChar buffer[G2_POS_MAX + 8];
56} g2state;
57
58/* ----------------------------------------------------------------- */
59
60static int G2liteObjCmdProc(ClientData clientData, Tcl_Interp *interp,
61 int objc, Tcl_Obj *CONST objv[])
62{
63 int size = 0;
64 int i = 0;
65 int j = 0;
66 Tcl_UniChar ch, tmp;
67 Tcl_UniChar *inbuffer = NULL;
68 Tcl_Obj *result = NULL;
69 Tcl_Obj *command_begin = NULL;
70 Tcl_Obj *command_append = NULL;
71 Tcl_Obj *command_end = NULL;
72
73 g2state g2;
74 g2.pos = 0;
75 g2.mode = G2_MODE_COPY;
76 g2.level = 0;
77
78 if(objc != 2)
79 {
80 Tcl_WrongNumArgs(interp, 1, objv, "string");
81 return TCL_ERROR;
82 }
83
84 inbuffer = Tcl_GetUnicodeFromObj(objv[1], &size);
85
86 result = Tcl_NewObj();
87 command_begin = Tcl_NewStringObj("variable g2result {}\n", -1);
88 command_append = Tcl_NewStringObj("\nappend g2result \"", -1);
89 command_end = Tcl_NewStringObj("\nreturn $g2result", -1);
90
91 Tcl_IncrRefCount(result);
92 Tcl_IncrRefCount(command_begin);
93 Tcl_IncrRefCount(command_append);
94 Tcl_IncrRefCount(command_end);
95
96 Tcl_AppendObjToObj(result, command_begin);
97
98 while(i < size)
99 {
100 ch = inbuffer[i++];
101
102 if(g2.pos >= G2_POS_MAX)
103 {
104 Tcl_AppendUnicodeToObj(result, g2.buffer, g2.pos);
105 g2.pos = 0;
106 }
107
108 /* if current symbol is @ */
109 if('@' == ch)
110 {
111 /* if previous symbol was @ => switch output mode */
112 if(g2.mode & G2_MODE_AT)
113 {
114 if(g2.mode & G2_MODE_COPY)
115 {
116 Tcl_AppendUnicodeToObj(result, g2.buffer, g2.pos);
117 Tcl_AppendObjToObj(result, command_append);
118 g2.pos = 0;
119 }
120 else
121 {
122 g2.buffer[g2.pos++] = '\"';
123 g2.buffer[g2.pos++] = '\n';
124 }
125
126 g2.mode ^= G2_MODE_COPY;
127 g2.mode |= G2_MODE_IGNORE_SPACES;
128 }
129
130 g2.mode ^= G2_MODE_AT;
131 continue;
132 }
133
134 /* current symbol is not @ */
135
136 if(g2.mode & G2_MODE_IGNORE_SPACES)
137 {
138 g2.mode ^= G2_MODE_IGNORE_SPACES;
139
140 /* if spaces => skip all spaces and new line character */
141 tmp = ch;
142 j = i;
143 while(j < size && Tcl_UniCharIsSpace(tmp) && '\n' != tmp)
144 {
145 tmp = inbuffer[j++];
146 }
147 if('\n' == tmp)
148 {
149 i = j;
150 continue;
151 }
152 }
153
154 /* if previous symbol was single @ => output @ */
155 if(g2.mode & G2_MODE_AT)
156 {
157 g2.mode ^= G2_MODE_AT;
158 g2.buffer[g2.pos++] = '@';
159 }
160
161 /* if output mode is COPY => output current symbol */
162 if(g2.mode & G2_MODE_COPY)
163 {
164 g2.buffer[g2.pos++] = ch;
165 continue;
166 }
167
168 /* output mode is not COPY *
169
170 /* if current symbol is $ */
171 if('$' == ch)
172 {
173 /* if previous symbol was $ => switch to variable substitute mode*/
174 if(g2.mode & G2_MODE_S)
175 {
176 g2.mode |= G2_MODE_VAR;
177 g2.level = 0;
178
179 g2.buffer[g2.pos++] = '$';
180 }
181
182 g2.mode ^= G2_MODE_S;
183 continue;
184 }
185
186 /* current symbol is not $ */
187
188 /* if previous symbol was single $ => output \$ */
189 if(g2.mode & G2_MODE_S)
190 {
191 g2.buffer[g2.pos++] = '\\';
192 g2.buffer[g2.pos++] = '$';
193 g2.mode ^= G2_MODE_S;
194 }
195
196 /* if in variable substitute mode => output current symbol, count { and } */
197 if(g2.mode & G2_MODE_VAR)
198 {
199 g2.buffer[g2.pos++] = ch;
200
201 /* if current symbol is { => stay in variable substitute mode */
202 if('{' == ch)
203 {
204 g2.level++;
205 }
206 else if('}' == ch)
207 {
208 g2.level--;
209 }
210
211 if(0 == g2.level)
212 {
213 g2.mode ^= G2_MODE_VAR;
214 }
215
216 continue;
217 }
218
219 /* not in variable substitute mode */
220
221 switch(ch)
222 {
223 case '\\':
224 case '{':
225 case '}':
226 case '[':
227 case ']':
228 case '\'':
229 case '"':
230 g2.buffer[g2.pos++] = '\\';
231 break;
232 }
233
234 g2.buffer[g2.pos++] = ch;
235 }
236
237 /* if last symbol was single @ => output @ */
238 if(g2.mode & G2_MODE_AT)
239 {
240 g2.buffer[g2.pos++] = '@';
241 }
242
243 /* if last symbol was single $ => output \$ */
244 if(g2.mode & G2_MODE_S)
245 {
246 g2.buffer[g2.pos++] = '\\';
247 g2.buffer[g2.pos++] = '$';
248 }
249
250 /* if output mode is not COPY => switch output mode */
251 if(!(g2.mode & G2_MODE_COPY))
252 {
253 g2.buffer[g2.pos++] = '\"';
254 g2.buffer[g2.pos++] = '\n';
255 }
256
257 if(g2.pos > 0)
258 {
259 Tcl_AppendUnicodeToObj(result, g2.buffer, g2.pos);
260 g2.pos = 0;
261 }
262
263 Tcl_AppendObjToObj(result, command_end);
264
265 Tcl_SetObjResult(interp, result);
266
267 Tcl_DecrRefCount(command_end);
268 Tcl_DecrRefCount(command_append);
269 Tcl_DecrRefCount(command_begin);
270 Tcl_DecrRefCount(result);
271
272 return TCL_OK;
273}
274
275/* ----------------------------------------------------------------- */
276
277int G2lite_Init(Tcl_Interp *interp)
278{
279 Tcl_CreateObjCommand(interp, "g2lite", G2liteObjCmdProc, 0, 0);
280 return Tcl_PkgProvide(interp, "g2lite", "0.1");
281}
Note: See TracBrowser for help on using the repository browser.