VAR \$[a-z_0-9]+ FUNC \%[a-z_0-9]+\[[a-z_0-9]+\] %x ASSIGNMENT_START %x ASSIGNMENT_WORD ASSIGNMENT_DOUBLE_QUOTES ASSIGNMENT_SINGLE_QUOTES %x ALTERNATE_TEST %x ALTERNATE_SKIP_FIRST ALTERNATE_USE_FIRST %x ALTERNATE_SKIP_SECOND ALTERNATE_USE_SECOND %{ /*************************************** WWWOFFLE - World Wide Web Offline Explorer - Version 2.9j. Parse the HTML to create the messages. ******************/ /****************** Written by Andrew M. Bishop This file Copyright 1998-201616 Andrew M. Bishop It may be distributed under the GNU Public License, version 2, or any higher version. See section COPYING of the GNU Public license for conditions under which this file may be redistributed. ***************************************/ #include "autoconfig.h" #include #include #include #ifdef __STDC__ #include #else #include #endif #include #include #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include #include #include "wwwoffle.h" #include "io.h" #include "misc.h" #include "errors.h" #include "config.h" #include "version.h" #ifndef O_BINARY /*+ A work-around for needing O_BINARY with Win32 to use binary mode. +*/ #define O_BINARY 0 #endif extern int msg_yylex(void); /* Local functions */ static char *html_message_body(int fd,char *template, va_list ap); static void write_or_append_string(char *str); static char /*@observer@*/ *add_variable(char *var,char *val); static void delete_variables(void); static char /*@observer@*/ *get_variable(char *var); static char *call_function(char *func); static void strip_trailing_whitespace(char *string); /* Local variables */ /*+ A known fixed empty string. +*/ static char *empty=""; /*+ The file descriptor that we are reading from. +*/ static int msg_yyfd=-1; /*+ The file descriptor that we are writing to. +*/ static int out_fd=-1; /*+ The string we are appending to. +*/ static char *out_str=NULL; /*+ The list of variables. +*/ static char **variables=NULL; /*+ The list of values. +*/ static char **values=NULL; /*+ The number of variables. +*/ static int nvariables=0; /*+ The option to use compression or chunked encoding for the reply. +*/ static int client_compression=0,client_chunked=0; /*++++++++++++++++++++++++++++++++++++++ Set the options to use for the socket sending the message. int compressed Use compression (and type). int chunked Use chunked encoding. ++++++++++++++++++++++++++++++++++++++*/ void SetMessageOptions(int compressed,int chunked) { client_compression=compressed; client_chunked=chunked; } /*++++++++++++++++++++++++++++++++++++++ Create a simple message using the template in the html directory. int fd The file descriptor to write it to. int status_val The numeric status value. char *status_str The status string. char *location A Location: HTTP header or NULL for none. char *template The name of the template for the message. ... A list of variable-value pairs to use in the parsing (NULL terminated). ++++++++++++++++++++++++++++++++++++++*/ void HTMLMessage(int fd,int status_val,char *status_str,char *location,char *template, ...) { va_list ap; if(location) HTMLMessageHead(fd,status_val,status_str, "Location",location, NULL); else HTMLMessageHead(fd,status_val,status_str, NULL); #ifdef __STDC__ va_start(ap,template); #else va_start(ap); #endif html_message_body(fd,template,ap); va_end(ap); } /*++++++++++++++++++++++++++++++++++++++ Create an html header using the specified fields. int fd The file descriptor to write it to. int status_val The numeric status value. char *status_str The status string. ... A list of variable-value pairs to use in the header (NULL terminated). ++++++++++++++++++++++++++++++++++++++*/ void HTMLMessageHead(int fd,int status_val,char *status_str, ...) { char *headline,*headerstr; char *var,*val; va_list ap; Header *header; int content_type=0; #ifdef __STDC__ va_start(ap,status_str); #else va_start(ap); #endif /* The start of the header */ headline=(char*)malloc(strlen(status_str)+16+MAX_INT_STR); sprintf(headline,"HTTP/1.0 %d %s\r\n",status_val,status_str); header=CreateHeader(headline,0); free(headline); AddToHeader(header,"Server","WWWOFFLE/" WWWOFFLE_VERSION); AddToHeader(header,"Date",RFC822Date(time(NULL),1)); /* Start filling in the header. */ while((var=va_arg(ap,char*))) { val=va_arg(ap,char*); if(!strcmp(var,"Content-Type")) content_type=1; if(val) AddToHeader(header,var,val); } va_end(ap); /* Set up compression header for the client if available and required. */ #if USE_ZLIB if(client_compression) { /* If it is not to be compressed then don't */ if(NotCompressed(GetHeader(header,"Content-Type"),NULL)) client_compression=0; /* Add the compression header for the client. */ else { if(client_compression==1) AddToHeader(header,"Content-Encoding","deflate"); else /* if(client_compression==2) */ AddToHeader(header,"Content-Encoding","gzip"); PrintMessage(Debug,"Using 'Content-Encoding: %s' for the client.", client_compression==1?"deflate":"gzip"); } } #endif /* Set up chunked encoding header for the client if required. */ if(client_chunked) { ChangeVersionInHeader(header,"HTTP/1.1"); AddToHeader(header,"Transfer-Encoding","chunked"); PrintMessage(Debug,"Using 'Transfer-Encoding: chunked' for the client."); } /* The end of the header. */ if(!content_type) AddToHeader(header,"Content-type","text/html"); AddToHeader(header,"Connection","close"); AddToHeader(header,"Proxy-Connection","close"); /* Write the header */ headerstr=HeaderString(header); if(StderrLevel==ExtraDebug) PrintMessage(ExtraDebug,"Reply Head (internal page)\n%s",headerstr); write_string(fd,headerstr); free(headerstr); FreeHeader(header); /* Initialise the client compression. */ #if USE_ZLIB if(client_compression) configure_io_zlib(fd,-1,client_compression); #endif /* Initialise the client chunked encoding. */ if(client_chunked) configure_io_chunked(fd,-1,1); } /*++++++++++++++++++++++++++++++++++++++ Create a HTML message body by passing the specified template through the micro-language processor. int fd The file descriptor to write to. char *template The name of the template for the message. ... A list of variable-value pairs to use in the parsing (NULL terminated). ++++++++++++++++++++++++++++++++++++++*/ void HTMLMessageBody(int fd,char *template, ...) { va_list ap; #ifdef __STDC__ va_start(ap,template); #else va_start(ap); #endif html_message_body(fd,template,ap); va_end(ap); } /*++++++++++++++++++++++++++++++++++++++ Create a HTML message string by passing the specified template through the micro-language processor. char *HTMLMessageString Returns a string containing the parsed template. char *template The name of the template for the message. ... A list of variable-value pairs to use in the parsing (NULL terminated). ++++++++++++++++++++++++++++++++++++++*/ char *HTMLMessageString(char *template, ...) { char *string; va_list ap; #ifdef __STDC__ va_start(ap,template); #else va_start(ap); #endif string=html_message_body(-1,template,ap); va_end(ap); return(string); } /*++++++++++++++++++++++++++++++++++++++ Finish up and free memory. ++++++++++++++++++++++++++++++++++++++*/ void FinishMessages(void) { delete_variables(); } /*++++++++++++++++++++++++++++++++++++++ Create a HTML message by passing the specified template through the micro-language processor. char *html_message_body Returns a string for the body or NULL when writing to file. int fd The file descriptor to write to (or -1 to create a string). char *template The name of the template for the message. va_list ap A list of variable-value pairs to use in the parsing (NULL terminated). ++++++++++++++++++++++++++++++++++++++*/ static char *html_message_body(int fd,char *template,va_list ap) { char *var,*val; char *filename; static int first=1; /* Set up the variables. */ out_fd=fd; out_str=NULL; if(fd==-1) delete_variables(); if(nvariables==0) { char *localurl=GetLocalURL(); add_variable("localurl",localurl); free(localurl); add_variable("version",WWWOFFLE_VERSION); } while((var=va_arg(ap,char*))) { val=va_arg(ap,char*); add_variable(var,val); } /* Open the file */ filename=(char*)malloc(16+strlen(template)); sprintf(filename,"messages/%s.html",template); msg_yyfd=OpenLanguageFile(filename); free(filename); if(msg_yyfd==-1) PrintMessage(Fatal,"Cannot open the message template '%s.html'.",template); init_io(msg_yyfd); /* Parse the template and fill in the gaps. */ if(!first) msg_yyrestart(NULL); msg_yylex(); finish_io(msg_yyfd); close(msg_yyfd); first=0; return(out_str); } /*++++++++++++++++++++++++++++++++++++++ Write the string to the file descriptor out_fd or append to the string out_str. char *str The string to write or append. ++++++++++++++++++++++++++++++++++++++*/ static void write_or_append_string(char *str) { if(out_fd==-1) { if(out_str) { out_str=(char*)realloc((void*)out_str,strlen(out_str)+strlen(str)+1); strcat(out_str,str); } else { out_str=(char*)malloc(256+strlen(str)); strcpy(out_str,str); } } else write_buffer_data(out_fd,str,strlen(str)); /* expect to make lots of small writes */ } /*++++++++++++++++++++++++++++++++++++++ Add a new variable. char *add_variable Returns the newly allocated variable. char *var The variable to add. char *val The value of the variable. ++++++++++++++++++++++++++++++++++++++*/ static char *add_variable(char *var,char *val) { int i; for(i=0;i[^\'\" \t\r\n=}] { yyless(0); BEGIN(ASSIGNMENT_WORD); } \" { BEGIN(ASSIGNMENT_DOUBLE_QUOTES); } \' { BEGIN(ASSIGNMENT_SINGLE_QUOTES); } [ \t\r]+ { } = { } \} { yyless(0); add_variable(var,NULL); free(var); BEGIN(previous); } \r*\n { add_variable(var,NULL); free(var); BEGIN(previous); } [^}$% \t\r\n] { APPEND_VAL(msg_yytext); } [$%] { APPEND_VAL(msg_yytext); } \\\} { APPEND_VAL(msg_yytext+1); } {VAR} { APPEND_VAL(get_variable(msg_yytext+1)); } {FUNC} { APPEND_VAL(call_function(msg_yytext+1)); } \} { yyless(0); add_variable(var,val); if(val)free(val); free(var); BEGIN(previous); } [ \t\r\n]+ { add_variable(var,val); if(val)free(val); free(var); BEGIN(previous); } [^\\\"$%]+ { APPEND_VAL(msg_yytext); } \\\" { APPEND_VAL(msg_yytext+1); } [$%\\] { APPEND_VAL(msg_yytext); } {VAR} { APPEND_VAL(get_variable(msg_yytext+1)); } {FUNC} { APPEND_VAL(call_function(msg_yytext+1)); } \" { add_variable(var,val); if(val)free(val); free(var); BEGIN(previous); } [^\\\'$%]+ { APPEND_VAL(msg_yytext); } \\\' { APPEND_VAL(msg_yytext+1); } [$%\\] { APPEND_VAL(msg_yytext); } {VAR} { APPEND_VAL(get_variable(msg_yytext+1)); } {FUNC} { APPEND_VAL(call_function(msg_yytext+1)); } \' { add_variable(var,val); if(val)free(val); free(var); BEGIN(previous); } [ \t]+ { } {VAR} { char *compare=get_variable(msg_yytext+1); do{in=input();} while(in!='{' && in!=EOF); if(!strcmp(val,compare)) BEGIN(ALTERNATE_USE_FIRST); else BEGIN(ALTERNATE_SKIP_FIRST); } [^\'\" \t\r\n{]+ { do{in=input();} while(in!='{' && in!=EOF); if(!strcmp(val,msg_yytext)) BEGIN(ALTERNATE_USE_FIRST); else BEGIN(ALTERNATE_SKIP_FIRST); } [\"\'\r\n{] { BEGIN(INITIAL); } [^}$%?\\\n]+ { write_or_append_string(msg_yytext); any++; } \n { if(any) write_or_append_string(msg_yytext); any=0; } \\[\"\'$%?\\{}] { write_or_append_string(msg_yytext+1); any++; } [$%\\?] { write_or_append_string(msg_yytext); any++; } {VAR} { write_or_append_string(get_variable(msg_yytext+1));any++; } {FUNC} { write_or_append_string(call_function(msg_yytext+1)); any++; } {VAR}[ \t]*/= { strip_trailing_whitespace(msg_yytext); var=(char*)malloc(strlen(msg_yytext)); strcpy(var,msg_yytext+1); previous=ALTERNATE_USE_FIRST; val=NULL; BEGIN(ASSIGNMENT_START); } \}[^{]*\{ { BEGIN(ALTERNATE_SKIP_SECOND); } \} { BEGIN(INITIAL); } [^\\}]+ { } \\\} { } \\ { } \}[^{]*\{ { BEGIN(ALTERNATE_USE_SECOND); } \} { BEGIN(INITIAL); } [^}$%?\\\n]+ { write_or_append_string(msg_yytext); any++; } \n { if(any) write_or_append_string(msg_yytext); any=0; } \\[\"\'$%?\\{}] { write_or_append_string(msg_yytext+1); any++; } [$%\\?] { write_or_append_string(msg_yytext); any++; } {VAR} { write_or_append_string(get_variable(msg_yytext+1)); any++; } {FUNC} { write_or_append_string(call_function(msg_yytext+1)); any++; } {VAR}[ \t]*/= { strip_trailing_whitespace(msg_yytext); var=(char*)malloc(strlen(msg_yytext)); strcpy(var,msg_yytext+1); previous=ALTERNATE_USE_SECOND; val=NULL; BEGIN(ASSIGNMENT_START); } \}[ \t]*\r*\n { BEGIN(INITIAL); if(any) write_or_append_string("\n"); any=0; } \}[ \t]+ { BEGIN(INITIAL); unput(' '); } \} { BEGIN(INITIAL); } [^\\\}]+ { } \\\} { } \\ { } \}[ \t]*\r*\n { BEGIN(INITIAL); if(any) write_or_append_string("\n"); any=0; } \}[ \t]+ { BEGIN(INITIAL); unput(' '); } \} { BEGIN(INITIAL); } /* End of file */ <> { BEGIN(INITIAL); return(0); } %%