1 VAR \$[a-z_0-9]+
2 FUNC \%[a-z_0-9]+\[[a-z_0-9]+\]
3
4 %x ASSIGNMENT_START
5 %x ASSIGNMENT_WORD ASSIGNMENT_DOUBLE_QUOTES ASSIGNMENT_SINGLE_QUOTES
6 %x ALTERNATE_TEST
7 %x ALTERNATE_SKIP_FIRST ALTERNATE_USE_FIRST
8 %x ALTERNATE_SKIP_SECOND ALTERNATE_USE_SECOND
9
10 %{
11 /***************************************
12 WWWOFFLE - World Wide Web Offline Explorer - Version 2.9j.
13
14 Parse the HTML to create the messages.
15 ******************/ /******************
16 Written by Andrew M. Bishop
17
18 This file Copyright 1998-201616 Andrew M. Bishop
19 It may be distributed under the GNU Public License, version 2, or
20 any higher version. See section COPYING of the GNU Public license
21 for conditions under which this file may be redistributed.
22 ***************************************/
23
24
25 #include "autoconfig.h"
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30
31 #ifdef __STDC__
32 #include <stdarg.h>
33 #else
34 #include <varargs.h>
35 #endif
36
37 #include <sys/types.h>
38 #include <unistd.h>
39
40 #if TIME_WITH_SYS_TIME
41 # include <sys/time.h>
42 # include <time.h>
43 #else
44 # if HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 # else
47 # include <time.h>
48 # endif
49 #endif
50
51 #include <sys/stat.h>
52 #include <fcntl.h>
53
54 #include "wwwoffle.h"
55 #include "io.h"
56 #include "misc.h"
57 #include "errors.h"
58 #include "config.h"
59 #include "version.h"
60
61
62 #ifndef O_BINARY
63 /*+ A work-around for needing O_BINARY with Win32 to use binary mode. +*/
64 #define O_BINARY 0
65 #endif
66
67
68 extern int msg_yylex(void);
69
70
71 /* Local functions */
72
73 static char *html_message_body(int fd,char *template, va_list ap);
74
75 static void write_or_append_string(char *str);
76
77 static char /*@observer@*/ *add_variable(char *var,char *val);
78 static void delete_variables(void);
79 static char /*@observer@*/ *get_variable(char *var);
80 static char *call_function(char *func);
81
82 static void strip_trailing_whitespace(char *string);
83
84
85 /* Local variables */
86
87 /*+ A known fixed empty string. +*/
88 static char *empty="";
89
90 /*+ The file descriptor that we are reading from. +*/
91 static int msg_yyfd=-1;
92
93 /*+ The file descriptor that we are writing to. +*/
94 static int out_fd=-1;
95
96 /*+ The string we are appending to. +*/
97 static char *out_str=NULL;
98
99 /*+ The list of variables. +*/
100 static char **variables=NULL;
101
102 /*+ The list of values. +*/
103 static char **values=NULL;
104
105 /*+ The number of variables. +*/
106 static int nvariables=0;
107
108 /*+ The option to use compression or chunked encoding for the reply. +*/
109 static int client_compression=0,client_chunked=0;
110
111
112 /*++++++++++++++++++++++++++++++++++++++
113 Set the options to use for the socket sending the message.
114
115 int compressed Use compression (and type).
116
117 int chunked Use chunked encoding.
118 ++++++++++++++++++++++++++++++++++++++*/
119
SetMessageOptions(int compressed,int chunked)120 void SetMessageOptions(int compressed,int chunked)
121 {
122 client_compression=compressed;
123 client_chunked=chunked;
124 }
125
126
127 /*++++++++++++++++++++++++++++++++++++++
128 Create a simple message using the template in the html directory.
129
130 int fd The file descriptor to write it to.
131
132 int status_val The numeric status value.
133
134 char *status_str The status string.
135
136 char *location A Location: HTTP header or NULL for none.
137
138 char *template The name of the template for the message.
139
140 ... A list of variable-value pairs to use in the parsing (NULL terminated).
141 ++++++++++++++++++++++++++++++++++++++*/
142
HTMLMessage(int fd,int status_val,char * status_str,char * location,char * template,...)143 void HTMLMessage(int fd,int status_val,char *status_str,char *location,char *template, ...)
144 {
145 va_list ap;
146
147 if(location)
148 HTMLMessageHead(fd,status_val,status_str,
149 "Location",location,
150 NULL);
151 else
152 HTMLMessageHead(fd,status_val,status_str,
153 NULL);
154
155 #ifdef __STDC__
156 va_start(ap,template);
157 #else
158 va_start(ap);
159 #endif
160
161 html_message_body(fd,template,ap);
162
163 va_end(ap);
164 }
165
166
167 /*++++++++++++++++++++++++++++++++++++++
168 Create an html header using the specified fields.
169
170 int fd The file descriptor to write it to.
171
172 int status_val The numeric status value.
173
174 char *status_str The status string.
175
176 ... A list of variable-value pairs to use in the header (NULL terminated).
177 ++++++++++++++++++++++++++++++++++++++*/
178
HTMLMessageHead(int fd,int status_val,char * status_str,...)179 void HTMLMessageHead(int fd,int status_val,char *status_str, ...)
180 {
181 char *headline,*headerstr;
182 char *var,*val;
183 va_list ap;
184 Header *header;
185 int content_type=0;
186
187 #ifdef __STDC__
188 va_start(ap,status_str);
189 #else
190 va_start(ap);
191 #endif
192
193 /* The start of the header */
194
195 headline=(char*)malloc(strlen(status_str)+16+MAX_INT_STR);
196 sprintf(headline,"HTTP/1.0 %d %s\r\n",status_val,status_str);
197 header=CreateHeader(headline,0);
198 free(headline);
199
200 AddToHeader(header,"Server","WWWOFFLE/" WWWOFFLE_VERSION);
201 AddToHeader(header,"Date",RFC822Date(time(NULL),1));
202
203 /* Start filling in the header. */
204
205 while((var=va_arg(ap,char*)))
206 {
207 val=va_arg(ap,char*);
208
209 if(!strcmp(var,"Content-Type"))
210 content_type=1;
211
212 if(val)
213 AddToHeader(header,var,val);
214 }
215
216 va_end(ap);
217
218 /* Set up compression header for the client if available and required. */
219
220 #if USE_ZLIB
221 if(client_compression)
222 {
223 /* If it is not to be compressed then don't */
224
225 if(NotCompressed(GetHeader(header,"Content-Type"),NULL))
226 client_compression=0;
227
228 /* Add the compression header for the client. */
229
230 else
231 {
232 if(client_compression==1)
233 AddToHeader(header,"Content-Encoding","deflate");
234 else /* if(client_compression==2) */
235 AddToHeader(header,"Content-Encoding","gzip");
236
237 PrintMessage(Debug,"Using 'Content-Encoding: %s' for the client.",
238 client_compression==1?"deflate":"gzip");
239 }
240 }
241 #endif
242
243 /* Set up chunked encoding header for the client if required. */
244
245 if(client_chunked)
246 {
247 ChangeVersionInHeader(header,"HTTP/1.1");
248 AddToHeader(header,"Transfer-Encoding","chunked");
249
250 PrintMessage(Debug,"Using 'Transfer-Encoding: chunked' for the client.");
251 }
252
253 /* The end of the header. */
254
255 if(!content_type)
256 AddToHeader(header,"Content-type","text/html");
257
258 AddToHeader(header,"Connection","close");
259 AddToHeader(header,"Proxy-Connection","close");
260
261 /* Write the header */
262
263 headerstr=HeaderString(header);
264
265 if(StderrLevel==ExtraDebug)
266 PrintMessage(ExtraDebug,"Reply Head (internal page)\n%s",headerstr);
267
268 write_string(fd,headerstr);
269
270 free(headerstr);
271
272 FreeHeader(header);
273
274 /* Initialise the client compression. */
275
276 #if USE_ZLIB
277 if(client_compression)
278 configure_io_zlib(fd,-1,client_compression);
279 #endif
280
281 /* Initialise the client chunked encoding. */
282
283 if(client_chunked)
284 configure_io_chunked(fd,-1,1);
285 }
286
287
288 /*++++++++++++++++++++++++++++++++++++++
289 Create a HTML message body by passing the specified template through the micro-language processor.
290
291 int fd The file descriptor to write to.
292
293 char *template The name of the template for the message.
294
295 ... A list of variable-value pairs to use in the parsing (NULL terminated).
296 ++++++++++++++++++++++++++++++++++++++*/
297
HTMLMessageBody(int fd,char * template,...)298 void HTMLMessageBody(int fd,char *template, ...)
299 {
300 va_list ap;
301
302 #ifdef __STDC__
303 va_start(ap,template);
304 #else
305 va_start(ap);
306 #endif
307
308 html_message_body(fd,template,ap);
309
310 va_end(ap);
311 }
312
313
314 /*++++++++++++++++++++++++++++++++++++++
315 Create a HTML message string by passing the specified template through the micro-language processor.
316
317 char *HTMLMessageString Returns a string containing the parsed template.
318
319 char *template The name of the template for the message.
320
321 ... A list of variable-value pairs to use in the parsing (NULL terminated).
322 ++++++++++++++++++++++++++++++++++++++*/
323
HTMLMessageString(char * template,...)324 char *HTMLMessageString(char *template, ...)
325 {
326 char *string;
327 va_list ap;
328
329 #ifdef __STDC__
330 va_start(ap,template);
331 #else
332 va_start(ap);
333 #endif
334
335 string=html_message_body(-1,template,ap);
336
337 va_end(ap);
338
339 return(string);
340 }
341
342
343 /*++++++++++++++++++++++++++++++++++++++
344 Finish up and free memory.
345 ++++++++++++++++++++++++++++++++++++++*/
346
FinishMessages(void)347 void FinishMessages(void)
348 {
349 delete_variables();
350 }
351
352
353 /*++++++++++++++++++++++++++++++++++++++
354 Create a HTML message by passing the specified template through the micro-language processor.
355
356 char *html_message_body Returns a string for the body or NULL when writing to file.
357
358 int fd The file descriptor to write to (or -1 to create a string).
359
360 char *template The name of the template for the message.
361
362 va_list ap A list of variable-value pairs to use in the parsing (NULL terminated).
363 ++++++++++++++++++++++++++++++++++++++*/
364
html_message_body(int fd,char * template,va_list ap)365 static char *html_message_body(int fd,char *template,va_list ap)
366 {
367 char *var,*val;
368 char *filename;
369 static int first=1;
370
371 /* Set up the variables. */
372
373 out_fd=fd;
374 out_str=NULL;
375
376 if(fd==-1)
377 delete_variables();
378
379 if(nvariables==0)
380 {
381 char *localurl=GetLocalURL();
382 add_variable("localurl",localurl);
383 free(localurl);
384 add_variable("version",WWWOFFLE_VERSION);
385 }
386
387 while((var=va_arg(ap,char*)))
388 {
389 val=va_arg(ap,char*);
390
391 add_variable(var,val);
392 }
393
394 /* Open the file */
395
396 filename=(char*)malloc(16+strlen(template));
397 sprintf(filename,"messages/%s.html",template);
398
399 msg_yyfd=OpenLanguageFile(filename);
400
401 free(filename);
402
403 if(msg_yyfd==-1)
404 PrintMessage(Fatal,"Cannot open the message template '%s.html'.",template);
405
406 init_io(msg_yyfd);
407
408 /* Parse the template and fill in the gaps. */
409
410 if(!first)
411 msg_yyrestart(NULL);
412
413 msg_yylex();
414
415 finish_io(msg_yyfd);
416 close(msg_yyfd);
417
418 first=0;
419
420 return(out_str);
421 }
422
423
424 /*++++++++++++++++++++++++++++++++++++++
425 Write the string to the file descriptor out_fd or append to the string out_str.
426
427 char *str The string to write or append.
428 ++++++++++++++++++++++++++++++++++++++*/
429
write_or_append_string(char * str)430 static void write_or_append_string(char *str)
431 {
432 if(out_fd==-1)
433 {
434 if(out_str)
435 {
436 out_str=(char*)realloc((void*)out_str,strlen(out_str)+strlen(str)+1);
437 strcat(out_str,str);
438 }
439 else
440 {
441 out_str=(char*)malloc(256+strlen(str));
442 strcpy(out_str,str);
443 }
444 }
445 else
446 write_buffer_data(out_fd,str,strlen(str)); /* expect to make lots of small writes */
447 }
448
449
450 /*++++++++++++++++++++++++++++++++++++++
451 Add a new variable.
452
453 char *add_variable Returns the newly allocated variable.
454
455 char *var The variable to add.
456
457 char *val The value of the variable.
458 ++++++++++++++++++++++++++++++++++++++*/
459
add_variable(char * var,char * val)460 static char *add_variable(char *var,char *val)
461 {
462 int i;
463
464 for(i=0;i<nvariables;i++)
465 if(!strcmp(var,variables[i]))
466 {
467 if(values[i]!=empty)
468 free(values[i]);
469 if(val)
470 {values[i]=(char*)malloc(strlen(val)+1); strcpy(values[i],val);}
471 else
472 values[i]=empty;
473
474 return(values[i]);
475 }
476
477 if(nvariables==0)
478 {
479 variables=(char**)malloc(8*sizeof(char*));
480 values =(char**)malloc(8*sizeof(char*));
481 }
482 else if(nvariables%8==0)
483 {
484 variables=(char**)realloc((void*)variables,(nvariables+8)*sizeof(char*));
485 values =(char**)realloc((void*)values ,(nvariables+8)*sizeof(char*));
486 }
487
488 variables[nvariables]=(char*)malloc(strlen(var)+1); strcpy(variables[nvariables],var);
489 if(val)
490 {values[nvariables]=(char*)malloc(strlen(val)+1); strcpy(values[nvariables],val);}
491 else
492 values[nvariables]=empty;
493
494 nvariables++;
495
496 return(values[nvariables-1]);
497 }
498
499
500 /*++++++++++++++++++++++++++++++++++++++
501 Delete all of the variables.
502 ++++++++++++++++++++++++++++++++++++++*/
503
delete_variables(void)504 static void delete_variables(void)
505 {
506 int i;
507
508 for(i=0;i<nvariables;i++)
509 {
510 free(variables[i]);
511 if(values[i]!=empty)
512 free(values[i]);
513 }
514
515 if(nvariables)
516 {
517 free(variables);
518 free(values);
519 nvariables=0;
520 variables=NULL;
521 values=NULL;
522 }
523 }
524
525
526 /*++++++++++++++++++++++++++++++++++++++
527 Get the value of the named variable.
528
529 char *get_variable Return the value of the variable or an empty string.
530
531 char *var The variable to get the value of.
532 ++++++++++++++++++++++++++++++++++++++*/
533
get_variable(char * var)534 static char *get_variable(char *var)
535 {
536 int i;
537
538 for(i=0;i<nvariables;i++)
539 if(!strcmp(var,variables[i]))
540 return(values[i]);
541
542 return(empty);
543 }
544
545
546 /*++++++++++++++++++++++++++++++++++++++
547 Call the named function with the specificied variable.
548
549 char *call_function Return the value of the function call.
550
551 char *func The function name to call, including the argument.
552 ++++++++++++++++++++++++++++++++++++++*/
553
call_function(char * func)554 static char *call_function(char *func)
555 {
556 char *var,*val,*result=NULL,*bracket1,*bracket2;
557
558 bracket1=strchr(func,'[');
559 *bracket1=0;
560 var=bracket1+1;
561 bracket2=strchr(var,']');
562 *bracket2=0;
563
564 val=get_variable(var);
565
566 if(val && !strcmp(func,"encode"))
567 result=URLEncodeFormArgs(val);
568 else if(val && !strcmp(func,"decode"))
569 {
570 char *ques=strchr(val,'?');
571 char *dec;
572
573 if(ques)
574 {
575 char *dec_path,*dec_args;
576
577 *ques=0;
578
579 dec_path=URLDecodeGeneric(val);
580 dec_args=URLDecodeFormArgs(ques+1);
581
582 dec=(char*)malloc(strlen(dec_path)+strlen(dec_args)+2);
583 strcpy(dec,dec_path);
584 strcat(dec,"?");
585 strcat(dec,dec_args);
586
587 *ques='?';
588
589 free(dec_path);
590 free(dec_args);
591 }
592 else
593 dec=URLDecodeGeneric(val);
594
595 result=HTMLString(dec,1);
596
597 free(dec);
598 }
599 else if(val && !strcmp(func,"html"))
600 {
601 result=HTMLString(val,1);
602 }
603 else
604 result=empty;
605
606 *bracket1='[';
607 *bracket2=']';
608
609 val=add_variable(func,result);
610
611 if(result && result!=empty)
612 free(result);
613
614 return(val);
615 }
616
617
618 /*++++++++++++++++++++++++++++++++++++++
619 Strip trailing white-space (this is done so that the lex is simpler, no variable trailing context).
620
621 char *string The string to strip the spaces from.
622 ++++++++++++++++++++++++++++++++++++++*/
623
strip_trailing_whitespace(char * string)624 static void strip_trailing_whitespace(char *string)
625 {
626 char *p=string;
627
628 while(*p && !isspace(*p))
629 p++;
630
631 *p=0;
632 }
633
634
635 #define YY_SKIP_YYWRAP 1 /* Remove error with prototype of ..._yywrap */
636 #ifndef msg_yywrap
637 /*+ Needed in lex but does nothing. +*/
638 #define msg_yywrap() 1
639 #endif
640
641 /*+ A macro to read data that can be used by the lexer. +*/
642 #define YY_INPUT(buf,result,max_size) \
643 { ssize_t temp=read_data(msg_yyfd,buf,max_size); result=(temp<0)?0:temp; }
644
645 /*+ A macro to append a string to the end of the existing one. +*/
646 #define APPEND_VAL(xxx) \
647 { \
648 char *XXX=xxx; \
649 if(val) \
650 { \
651 val=(char*)realloc((void*)val,strlen(val)+strlen(XXX)+1); \
652 strcat(val,XXX); \
653 } \
654 else \
655 { \
656 val=(char*)malloc(strlen(XXX)+1); \
657 strcpy(val,XXX); \
658 } \
659 }
660
661 %}
662
663 %%
664 /* Can use local variables since the parser only returns at EOF. */
665 char *var=NULL;
666 char *val=NULL;
667 int previous=INITIAL;
668 int any=0,in;
669
670 [^$%?\\\n \t]+ { write_or_append_string(msg_yytext); any++; }
671 \n { write_or_append_string(msg_yytext); any=0; }
672 \\[\"\'$%?\\{}] { write_or_append_string(msg_yytext+1); any++; }
673 [$%\\?] { write_or_append_string(msg_yytext); any++; }
674
675 [ \t]+ { write_or_append_string(msg_yytext); any++; }
676 [ \t]*\\\r*\n { }
677
678 {VAR} { write_or_append_string(get_variable(msg_yytext+1)); }
679 {VAR}[ \t]*/= { strip_trailing_whitespace(msg_yytext);
680 var=(char*)malloc(strlen(msg_yytext)); strcpy(var,msg_yytext+1);
681 previous=INITIAL; val=NULL; BEGIN(ASSIGNMENT_START); }
682 {VAR}[ \t]*/\? { strip_trailing_whitespace(msg_yytext);
683 val=get_variable(msg_yytext+1); do{in=input();} while(in!='{' && in!=EOF);
684 if(*val) BEGIN(ALTERNATE_USE_FIRST); else BEGIN(ALTERNATE_SKIP_FIRST); }
685 {VAR}[ \t]*/\?= { strip_trailing_whitespace(msg_yytext);
686 val=get_variable(msg_yytext+1); do{in=input();} while(in!='=' && in!=EOF);
687 BEGIN(ALTERNATE_TEST); }
688
689 {FUNC} { write_or_append_string(call_function(msg_yytext+1)); }
690
691 <ASSIGNMENT_START>[^\'\" \t\r\n=}] { yyless(0); BEGIN(ASSIGNMENT_WORD); }
692 <ASSIGNMENT_START>\" { BEGIN(ASSIGNMENT_DOUBLE_QUOTES); }
693 <ASSIGNMENT_START>\' { BEGIN(ASSIGNMENT_SINGLE_QUOTES); }
694 <ASSIGNMENT_START>[ \t\r]+ { }
695 <ASSIGNMENT_START>= { }
696 <ASSIGNMENT_START>\} { yyless(0); add_variable(var,NULL); free(var); BEGIN(previous); }
697 <ASSIGNMENT_START>\r*\n { add_variable(var,NULL); free(var); BEGIN(previous); }
698
699
700 <ASSIGNMENT_WORD>[^}$% \t\r\n] { APPEND_VAL(msg_yytext); }
701 <ASSIGNMENT_WORD>[$%] { APPEND_VAL(msg_yytext); }
702 <ASSIGNMENT_WORD>\\\} { APPEND_VAL(msg_yytext+1); }
703 <ASSIGNMENT_WORD>{VAR} { APPEND_VAL(get_variable(msg_yytext+1)); }
704 <ASSIGNMENT_WORD>{FUNC} { APPEND_VAL(call_function(msg_yytext+1)); }
705 <ASSIGNMENT_WORD>\} { yyless(0); add_variable(var,val); if(val)free(val); free(var); BEGIN(previous); }
706 <ASSIGNMENT_WORD>[ \t\r\n]+ { add_variable(var,val); if(val)free(val); free(var); BEGIN(previous); }
707
708 <ASSIGNMENT_DOUBLE_QUOTES>[^\\\"$%]+ { APPEND_VAL(msg_yytext); }
709 <ASSIGNMENT_DOUBLE_QUOTES>\\\" { APPEND_VAL(msg_yytext+1); }
710 <ASSIGNMENT_DOUBLE_QUOTES>[$%\\] { APPEND_VAL(msg_yytext); }
711 <ASSIGNMENT_DOUBLE_QUOTES>{VAR} { APPEND_VAL(get_variable(msg_yytext+1)); }
712 <ASSIGNMENT_DOUBLE_QUOTES>{FUNC} { APPEND_VAL(call_function(msg_yytext+1)); }
713 <ASSIGNMENT_DOUBLE_QUOTES>\" { add_variable(var,val); if(val)free(val); free(var); BEGIN(previous); }
714
715 <ASSIGNMENT_SINGLE_QUOTES>[^\\\'$%]+ { APPEND_VAL(msg_yytext); }
716 <ASSIGNMENT_SINGLE_QUOTES>\\\' { APPEND_VAL(msg_yytext+1); }
717 <ASSIGNMENT_SINGLE_QUOTES>[$%\\] { APPEND_VAL(msg_yytext); }
718 <ASSIGNMENT_SINGLE_QUOTES>{VAR} { APPEND_VAL(get_variable(msg_yytext+1)); }
719 <ASSIGNMENT_SINGLE_QUOTES>{FUNC} { APPEND_VAL(call_function(msg_yytext+1)); }
720 <ASSIGNMENT_SINGLE_QUOTES>\' { add_variable(var,val); if(val)free(val); free(var); BEGIN(previous); }
721
722
723 <ALTERNATE_TEST>[ \t]+ { }
724 <ALTERNATE_TEST>{VAR} { char *compare=get_variable(msg_yytext+1);
725 do{in=input();} while(in!='{' && in!=EOF);
726 if(!strcmp(val,compare)) BEGIN(ALTERNATE_USE_FIRST); else BEGIN(ALTERNATE_SKIP_FIRST); }
727 <ALTERNATE_TEST>[^\'\" \t\r\n{]+ { do{in=input();} while(in!='{' && in!=EOF);
728 if(!strcmp(val,msg_yytext)) BEGIN(ALTERNATE_USE_FIRST); else BEGIN(ALTERNATE_SKIP_FIRST); }
729 <ALTERNATE_TEST>[\"\'\r\n{] { BEGIN(INITIAL); }
730
731
732 <ALTERNATE_USE_FIRST>[^}$%?\\\n]+ { write_or_append_string(msg_yytext); any++; }
733 <ALTERNATE_USE_FIRST>\n { if(any) write_or_append_string(msg_yytext); any=0; }
734 <ALTERNATE_USE_FIRST>\\[\"\'$%?\\{}] { write_or_append_string(msg_yytext+1); any++; }
735 <ALTERNATE_USE_FIRST>[$%\\?] { write_or_append_string(msg_yytext); any++; }
736 <ALTERNATE_USE_FIRST>{VAR} { write_or_append_string(get_variable(msg_yytext+1));any++; }
737 <ALTERNATE_USE_FIRST>{FUNC} { write_or_append_string(call_function(msg_yytext+1)); any++; }
738 <ALTERNATE_USE_FIRST>{VAR}[ \t]*/= { strip_trailing_whitespace(msg_yytext);
739 var=(char*)malloc(strlen(msg_yytext)); strcpy(var,msg_yytext+1);
740 previous=ALTERNATE_USE_FIRST; val=NULL; BEGIN(ASSIGNMENT_START); }
741 <ALTERNATE_USE_FIRST>\}[^{]*\{ { BEGIN(ALTERNATE_SKIP_SECOND); }
742 <ALTERNATE_USE_FIRST>\} { BEGIN(INITIAL); }
743
744
745 <ALTERNATE_SKIP_FIRST>[^\\}]+ { }
746 <ALTERNATE_SKIP_FIRST>\\\} { }
747 <ALTERNATE_SKIP_FIRST>\\ { }
748 <ALTERNATE_SKIP_FIRST>\}[^{]*\{ { BEGIN(ALTERNATE_USE_SECOND); }
749 <ALTERNATE_SKIP_FIRST>\} { BEGIN(INITIAL); }
750
751
752 <ALTERNATE_USE_SECOND>[^}$%?\\\n]+ { write_or_append_string(msg_yytext); any++; }
753 <ALTERNATE_USE_SECOND>\n { if(any) write_or_append_string(msg_yytext); any=0; }
754 <ALTERNATE_USE_SECOND>\\[\"\'$%?\\{}] { write_or_append_string(msg_yytext+1); any++; }
755 <ALTERNATE_USE_SECOND>[$%\\?] { write_or_append_string(msg_yytext); any++; }
756 <ALTERNATE_USE_SECOND>{VAR} { write_or_append_string(get_variable(msg_yytext+1)); any++; }
757 <ALTERNATE_USE_SECOND>{FUNC} { write_or_append_string(call_function(msg_yytext+1)); any++; }
758 <ALTERNATE_USE_SECOND>{VAR}[ \t]*/= { strip_trailing_whitespace(msg_yytext);
759 var=(char*)malloc(strlen(msg_yytext)); strcpy(var,msg_yytext+1);
760 previous=ALTERNATE_USE_SECOND; val=NULL; BEGIN(ASSIGNMENT_START); }
761 <ALTERNATE_USE_SECOND>\}[ \t]*\r*\n { BEGIN(INITIAL); if(any) write_or_append_string("\n"); any=0; }
762 <ALTERNATE_USE_SECOND>\}[ \t]+ { BEGIN(INITIAL); unput(' '); }
763 <ALTERNATE_USE_SECOND>\} { BEGIN(INITIAL); }
764
765
766 <ALTERNATE_SKIP_SECOND>[^\\\}]+ { }
767 <ALTERNATE_SKIP_SECOND>\\\} { }
768 <ALTERNATE_SKIP_SECOND>\\ { }
769 <ALTERNATE_SKIP_SECOND>\}[ \t]*\r*\n { BEGIN(INITIAL); if(any) write_or_append_string("\n"); any=0; }
770 <ALTERNATE_SKIP_SECOND>\}[ \t]+ { BEGIN(INITIAL); unput(' '); }
771 <ALTERNATE_SKIP_SECOND>\} { BEGIN(INITIAL); }
772
773 /* End of file */
774
775 <<EOF>> { BEGIN(INITIAL); return(0); }
776
777 %%
778