-- init_compile_env
[silentbob2.git] / sblib / the_tt.cxx
blobcfba0c24cc0171873ae976935be51874c88098b7
1 /*
2 * (c) Oleg Puchinin 2006,2007,2008
3 * graycardinalster@gmail.com
4 *
5 */
7 /*
8 * "Oleg, THE_TT and BUGs"
9 *
10 * 01/01/06 00:00 - Started...
11 * January 2006 - string BUG fixed.
12 * "//" BUG fixed. It's work currently ?!
14 * January 2006, last day. added operator to line conversion.
15 * February 2006 - operator to line conversion work properly.
16 * February 2006 - "macro BUG" fixed.
17 * March 2006 - "Style BUG" fixed (?).
18 * January 2008 - C# patch.
19 **/
21 #include <head.h>
22 #include <bob_flags.h>
23 #include <sys/mman.h>
24 #include <the_tt.h>
26 extern FILE * d_stream_dbg;
28 namespace THE_TT {
30 #define IF(arg) if (t_map[ipos] == arg)
31 #define IF2(arga, argb) if (t_map[ipos] == arga && t_map[ipos+1] == argb)
32 #define is_space(arg) (arg == ' ' || arg == '\t' || arg == '\n')
33 #define IF_breaker if (t_map[ipos]==';' || t_map[ipos] == '}' || t_map[ipos] == '{')
34 #define T t_map[ipos]
35 #define T2 t_map[ipos+1]
36 #define Toff(arg) t_map[ipos+arg]
37 #define ATTACH t_attach ();
39 int ipos;
40 int opos;
41 int t_size;
42 char * t_map;
43 char * t_new;
44 int t_current_line;
45 int t_op_no;
46 int brace_depth = 0; // for '()'
47 int block_depth = 0; // for '{}'
48 bool b_make_attachment;
49 bool t_in_macro;
50 pair_t * d_attachment = NULL;
51 char * tt_out_buf = NULL;
52 int tt_outbuf_size = 0;
53 unsigned int t_spaces;
54 bool b_mustlined;
55 bool b_instring;
56 bool b_newline;
57 int d_slash_count;
58 bool b_lined;
59 char ch_last;
60 bool b_sharp;
62 inline void t_attach ()
64 t_op_no++;
65 d_attachment[t_op_no].pair_op = t_op_no;
66 d_attachment[t_op_no].pair_line = t_current_line;
67 d_attachment[t_op_no].offset = ipos;
68 brace_depth = 0; // Paranoid
71 inline void TN (char arg)
73 t_new[opos] = arg;
74 ++opos;
75 if (arg == '\n' ||
76 arg == '{' || arg == '}' ||
77 (arg == ';' && !brace_depth)) {
79 if (arg == '\n') {
80 --t_current_line;
81 ATTACH;
82 ++t_current_line;
83 } else
84 ATTACH;
88 #define TNs(arg) do { t_new[opos] = arg; ++opos; } while (0)
90 inline void tt_comment ()
92 while (ipos < t_size) {
93 IF2('*', '/')
94 break;
95 IF ('\n') {
96 t_current_line++;
98 ++ipos;
100 ++ipos;
103 inline void tt_skip ()
105 while (T != '\n' && ipos < t_size)
106 ++ipos;
107 --ipos;
110 void tt_init (char * d_input, int t_new_size, char * d_output)
112 t_spaces = 1;
113 b_mustlined = false;
114 b_instring = false;
115 b_newline = true;
116 d_slash_count = 0;
117 b_lined = true;
118 ch_last = 0;
119 b_sharp = false;
121 ipos = 0;
122 opos = 0;
123 b_lined = true;
124 b_mustlined = false;
125 b_newline = true;
126 t_size = t_new_size;
127 t_map = d_input;
128 t_new = d_output;
129 t_current_line = 0;
130 t_op_no = 0;
131 brace_depth = 0;
132 block_depth = 0;
135 bool tt_process_line ()
137 if (b_instring && ch_last != T) {
138 TN(T);
139 return true;
142 if (b_instring) {
143 if (b_sharp || (Toff(-1) != '\\')) { // \" and... \\" :)
144 b_instring = false;
145 b_sharp = false;
146 } else {
147 d_slash_count = 1;
148 while (Toff (-(d_slash_count)) == '\\') // Yes, I'm don't like this.
149 d_slash_count++;
151 if (d_slash_count & 1) {
152 b_instring = false;
153 b_sharp = false;
156 } else { // !b_instring
157 ch_last = T;
158 b_instring = true;
159 if (Toff (-1) == '@')
160 b_sharp = true;
163 return false;
166 void tt_process_space ()
168 if (T == '\n') {
169 b_newline = true;
170 if (Toff(1) == '#' && !b_lined) {
171 TN ('\n');
172 ++t_spaces;
173 b_lined = true;
174 b_mustlined = false;
175 return;
178 if (b_mustlined) {
179 TN('\n');
180 ++t_spaces;
181 if (!(Toff (-1) == '\\')) {
182 b_mustlined = false;
183 b_lined = true;
187 if (t_spaces == 0 && !b_lined) {
188 ++t_spaces;
189 TN(' ');
191 return;
192 } else {
193 ++t_spaces;
194 if (t_spaces == 1)
195 TN(' ');
198 return;
201 // NOTE: you _must_ allocate d_input and d_output before call this.
202 int the_tt_for_buffers (char * d_input,
203 int t_new_size,
204 char * d_output)
206 tt_init (d_input, t_new_size, d_output);
208 if (t_map[0] == '\n') {
209 ++ipos; // "mmap BUG" fixed :))
210 ++t_current_line;
213 if (Toff (t_size-1) == '\n')
214 t_size--; // mmap'ed TT do not work without this !
216 for (; ipos < t_size; ++ipos) {
217 if (if_abc (&t_map[ipos]) || if_digit (&t_map[ipos])) {
218 b_lined = false;
219 t_spaces = 0;
220 goto abc;
223 IF ('\n')
224 ++t_current_line;
226 if (T == '\'' || T == '\"') {
227 if (tt_process_line ())
228 continue;
231 if (b_instring) {
232 if (T != '\n')
233 TNs (T);
234 else {
235 if (Toff(-1) == '\\')
236 --opos;
238 continue;
241 if (T == '\n') {
242 if (Toff(-1) == '\\') {
243 if (t_in_macro)
244 TN(T);
245 else
246 --opos;
247 continue;
248 } else
249 t_in_macro = false;
252 IF2('/','/') {
253 tt_skip ();
254 continue;
257 IF2('/', '*') {
258 tt_comment ();
259 continue;
262 switch (T) {
263 case '(':
264 ++brace_depth;
265 break;
266 case ')':
267 --brace_depth;
268 break;
271 if (brace_depth < 0)
272 brace_depth = 0;
274 if (is_space (T)) {
275 tt_process_space ();
276 continue;
279 b_lined = false;
280 if (T == '(' && t_spaces == 0 && b_mustlined == 0) {
281 ++t_spaces; // No space after '('.
282 TN(' ');
283 TN('(');
284 continue;
287 if (T == ')' && t_spaces == 0) {
288 ++t_spaces;
289 TN(')');
290 TN(' ');
291 continue;
294 t_spaces = 0;
295 IF_breaker {
296 TN(T);
297 TN(' ');
298 ++t_spaces;
299 continue;
302 IF('#' && b_newline) {
303 TN ('#');
304 t_in_macro = true;
305 b_mustlined = true;
306 continue;
309 IF (0x0D)
310 continue;
312 abc:
313 b_newline = false;
314 TNs(T);
315 } // for
317 return opos;
320 char * do_tt_file (tt_state_t * d_tt_state)
322 char * t_output = NULL;
323 char * f_name;
324 int t_Ret;
326 d_attachment = NULL;
328 if (! d_tt_state)
329 return 0;
331 f_name = d_tt_state->fileName;
333 if (EQ(f_name, "-")) {
334 d_tt_state->fileData = Dread_to_eof (fileno (stdin), &d_tt_state->fileDataSize);
335 if (d_tt_state->fileDataSize <= 0)
336 exit (1);
337 } else {
338 if (tt_map (d_tt_state) < 0)
339 return NULL;
342 t_size = d_tt_state->fileDataSize;
343 t_output = CNEW (char, t_size<<1); // Paranoid.
345 if (t_size < 4096)
346 d_attachment = CNEW (pair_t, 4096);
347 else
348 d_attachment = CNEW (pair_t, t_size>>1);
349 d_tt_state->attachment = d_attachment;
351 t_Ret = the_tt_for_buffers (d_tt_state->fileData, t_size, t_output);
352 t_output[t_Ret] = 0; // Required.
353 d_tt_state->resultSize = t_Ret;
354 d_tt_state->result = t_output;
356 return t_output;
359 // $ silent_bob --the-tt
360 int the_tt_main (char * f_name)
362 char * t_output;
363 tt_state_t * d_tt_state;
365 d_tt_state = CNEW (tt_state_t, 1);
366 memset (d_tt_state, 0, sizeof (tt_state_t));
367 d_tt_state->fileName = f_name;
368 t_output = do_tt_file (d_tt_state);
370 if (! SB_FLGET (SB_FLSIMULATE))
371 write (fileno (stdout), t_output, d_tt_state->resultSize);
373 free_tt_state (d_tt_state);
374 return EXIT_SUCCESS;
377 } // namespace THE_TT
379 void free_tt_state (struct tt_state_t * S)
381 if (S->mmaped)
382 munmap (S->fileData, S->fileDataSize);
383 else
384 DROP (S->fileData);
386 if (S->fd)
387 close (S->fd);
389 DROP (S->result);
390 DROP (S->attachment);
391 DROP (S);
394 int tt_map (tt_state_t *tt)
396 tt->mmaped = true;
397 tt->fileData = DFMAP (tt->fileName, &tt->fd, &tt->fileDataSize);
399 if (tt->fileData == NULL) {
400 tt->fileDataSize = fsize (tt->fileName);
401 tt->mmaped = false;
402 tt->fileData = CNEW (char, tt->fileDataSize);
403 if (Dfnread (tt->fileName, tt->fileData, tt->fileDataSize) < 0)
404 DROP (tt->fileData);
407 if (! tt->fileData) {
408 fprintf (stderr, "can't open/mmap file %s\n", tt->fileName);
409 perror ("open/mmap");
410 return -1;
413 return 0;