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