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 |
|
---|
39 | enum
|
---|
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 |
|
---|
50 | typedef 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 |
|
---|
60 | static 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 |
|
---|
277 | int G2lite_Init(Tcl_Interp *interp)
|
---|
278 | {
|
---|
279 | Tcl_CreateObjCommand(interp, "g2lite", G2liteObjCmdProc, 0, 0);
|
---|
280 | return Tcl_PkgProvide(interp, "g2lite", "0.1");
|
---|
281 | }
|
---|