/** * scanner.l * * Copyright (C) 2003 - 2005 Bojan Smojver, Rexursive * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licence as published by the Free * Software Foundation; either version 2 of the Licence, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licence for * more details. * * You should have received a copy of the GNU General Public Licence along * with this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA * * In addition, as two special exceptions, Bojan Smojver, Rexursive, gives * permission to: * * 1. Link, both statically and dynamically, the code of this program with * Apache HTTP Server, Apache Portable Runtime and Apache Portable Runtime * Utility Library from Apache Software Foundation (or with modified versions * of the above, that use the same licence - Apache Software Licence 1.1, 2.0 * or any later version), and distribute linked combinations including the * program and the above software from Apache Software Foundation. You must * obey the GNU General Public Licence in all respects for all of the code * used other than Apache HTTP Server, Apache Portable Runtime and Apache * Portable Runtime Utility Library. * * 2. Dynamically link any shared library with this program at run-time, * through the interface of SpinApplication or LoadModule run-time * configuration directives of Apache HTTP Server, as provided by this program * or Apache HTTP Server itself, regardless of licensing terms of those shared * libraries. You must obey the GNU General Public Licence in all respects for * all of the code used other than that of those shared libraries. * * If you modify this file, you may extend these exceptions to your version of * the file, but you are not obligated to do so. If you do not wish to do so, * delete one or both of these exception statements from your version. * */ %{ #include "private.h" #define YY_READ_BUF_SIZE 65536 #define YY_DECL int rxv_spin_lex(YYSTYPE *yylval_param,yyscan_t yyscanner) #include "parser.h" %} %option 8bit reentrant bison-bridge stack %option warn nodefault %option never-interactive %option full %option noyywrap %option header-file="scanner.h" %option backup REF \$[#@]*\{[[:alpha:]][[:alnum:]_-]*(\.[[:alpha:]][[:alnum:]_-]*)*\} REG \/([^/]|\\\/)*\/ LIT \"([^"]|\\\")*\" %x command %% /* initial scanner */ {REF} { size_t chunks,noff=2; int ldepth; char *p; rxv_spin_ref_t *ref; rxv_spin_node_t *node=apr_pcalloc(yyextra->tpool,sizeof(*node)); if(!node){ yyextra->error="out of memory"; return ERR; } if(yyextra->istxt){ rxv_spin_txt_t *txt=apr_palloc(yyextra->tpool,sizeof(*txt)); if(!txt){ yyextra->error="out of memory"; return ERR; } txt->offset=yyextra->offset; txt->length=yyextra->length; /* pick up the cached text */ if(yyextra->cacheall || txt->lengthcache=apr_pmemdup(yyextra->tpool,yyextra->buf,txt->length))){ yyextra->error="out of memory"; return ERR; } } else{ txt->cache=NULL; } node->type=RXV_SPIN_TXT; node->txt=txt; yyless(0); yyextra->offset+=yyextra->length; yyextra->istxt=0; *yylval=node; return TXT; } if(!(ref=apr_pcalloc(yyextra->tpool,sizeof(*ref)))){ yyextra->error="out of memory"; return ERR; } /* populate node */ node->type=RXV_SPIN_REF; node->ref=ref; if(*(yytext+1)=='#' || *(yytext+1)=='@') noff++; if(!(ref->name=apr_pstrmemdup(yyextra->tpool,yytext+noff,yyleng-(noff+1)))){ yyextra->error="out of memory"; return ERR; } /* count chunks of the name */ for(chunks=0,p=ref->name;p;p=strchr(p,'.')){ p++; chunks++; } /* find the last part of the reference name */ if((ref->chunk=strrchr(ref->name,'.'))){ if(!(ref->chunk=apr_pstrmemdup(yyextra->tpool,ref->chunk+1, strlen(ref->name)-(ref->chunk-ref->name)-1))){ yyextra->error="out of memory"; return ERR; } } else{ ref->chunk=ref->name; } /* link the index of the nesting for loop */ for(ldepth=yyextra->ldepth-1;ldepth>=0 && !ref->loop;ldepth--){ char *name=(*(yyextra->loop+ldepth))->ref->name; size_t length=strlen(name); if(lengthname,length) && *(ref->name+length)=='.' && !strchr(ref->name+length+1,'.')) ref->loop=*(yyextra->loop+ldepth); } /* impossible reference, ignore */ if(chunks>1 && !ref->loop) node=NULL; yyextra->offset+=yyleng; yyextra->col+=yyleng; yyextra->istxt=0; *yylval=node; switch(*(yytext+1)){ case '#': ref->type=RXV_SPIN_REF_SIZ; break; case '@': ref->type=RXV_SPIN_REF_IND; break; default: ref->type=RXV_SPIN_REF_REG; break; } return REF; } "#for" { rxv_spin_for_t *loop; rxv_spin_node_t *node=apr_pcalloc(yyextra->tpool,sizeof(*node)); if(!node){ yyextra->error="out of memory"; return ERR; } if(yyextra->istxt){ rxv_spin_txt_t *txt=apr_palloc(yyextra->tpool,sizeof(*txt)); if(!txt){ yyextra->error="out of memory"; return ERR; } txt->offset=yyextra->offset; txt->length=yyextra->length; /* pick up the cached text */ if(yyextra->cacheall || txt->lengthcache=apr_pmemdup(yyextra->tpool,yyextra->buf,txt->length))){ yyextra->error="out of memory"; return ERR; } } else{ txt->cache=NULL; } node->type=RXV_SPIN_TXT; node->txt=txt; yyless(0); yyextra->offset+=yyextra->length; yyextra->istxt=0; *yylval=node; return TXT; } if(!(loop=apr_pcalloc(yyextra->tpool,sizeof(*loop)))){ yyextra->error="out of memory"; return ERR; } /* populate node */ node->type=RXV_SPIN_FOR; node->loop=loop; *(yyextra->loop+yyextra->ldepth)=loop; *(yyextra->nest+yyextra->depth)=RXV_SPIN_FOR; yyextra->offset+=yyleng; yyextra->col+=yyleng; yyextra->istxt=0; yyextra->depth++; yyextra->ldepth++; *(yyextra->boff+yyextra->depth)=0; if(yyextra->depth>=RXV_SPIN_MAX_DEPTH){ yyextra->error="maximum nesting depth exceeded"; return ERR; } yy_push_state(command,yyscanner); *yylval=node; return FOR; } "#if"|"#unless" { rxv_spin_if_t *cond; rxv_spin_node_t *node=apr_pcalloc(yyextra->tpool,sizeof(*node)); if(!node){ yyextra->error="out of memory"; return ERR; } if(yyextra->istxt){ rxv_spin_txt_t *txt=apr_palloc(yyextra->tpool,sizeof(*txt)); if(!txt){ yyextra->error="out of memory"; return ERR; } txt->offset=yyextra->offset; txt->length=yyextra->length; /* pick up the cached text */ if(yyextra->cacheall || txt->lengthcache=apr_pmemdup(yyextra->tpool,yyextra->buf,txt->length))){ yyextra->error="out of memory"; return ERR; } } else{ txt->cache=NULL; } node->type=RXV_SPIN_TXT; node->txt=txt; yyless(0); yyextra->offset+=yyextra->length; yyextra->istxt=0; *yylval=node; return TXT; } if(!(cond=apr_pcalloc(yyextra->tpool,sizeof(*cond)))){ yyextra->error="out of memory"; return ERR; } /* are we if (always 0) or unless (always 1) */ if(*(yytext+1)=='u') cond->type=RXV_SPIN_IF_UNLESS; /* populate node */ node->type=RXV_SPIN_IF; node->cond=cond; *(yyextra->nest+yyextra->depth)=RXV_SPIN_IF; yyextra->offset+=yyleng; yyextra->col+=yyleng; yyextra->istxt=0; yyextra->depth++; *(yyextra->boff+yyextra->depth)=0; if(yyextra->depth>=RXV_SPIN_MAX_DEPTH){ yyextra->error="maximum nesting depth exceeded"; return ERR; } yy_push_state(command,yyscanner); *yylval=node; return IF; } "#else" { if(yyextra->istxt){ rxv_spin_node_t *node=apr_pcalloc(yyextra->tpool,sizeof(*node)); rxv_spin_txt_t *txt=apr_palloc(yyextra->tpool,sizeof(*txt)); if(!(node && txt)){ yyextra->error="out of memory"; return ERR; } txt->offset=yyextra->offset; txt->length=yyextra->length; /* pick up the cached text */ if(yyextra->cacheall || txt->lengthcache=apr_pmemdup(yyextra->tpool,yyextra->buf,txt->length))){ yyextra->error="out of memory"; return ERR; } } else{ txt->cache=NULL; } node->type=RXV_SPIN_TXT; node->txt=txt; yyless(0); yyextra->offset+=yyextra->length; yyextra->istxt=0; *yylval=node; return TXT; } *(yyextra->boff+yyextra->depth)=RXV_SPIN_MAX_DEPTH; yyextra->offset+=yyleng; yyextra->col+=yyleng; yyextra->istxt=0; yylval=NULL; return ELSE; } "#end" { if(yyextra->istxt){ rxv_spin_node_t *node=apr_pcalloc(yyextra->tpool,sizeof(*node)); rxv_spin_txt_t *txt=apr_palloc(yyextra->tpool,sizeof(*txt)); if(!(node && txt)){ yyextra->error="out of memory"; return ERR; } txt->offset=yyextra->offset; txt->length=yyextra->length; /* pick up the cached text */ if(yyextra->cacheall || txt->lengthcache=apr_pmemdup(yyextra->tpool,yyextra->buf,txt->length))){ yyextra->error="out of memory"; return ERR; } } else{ txt->cache=NULL; } node->type=RXV_SPIN_TXT; node->txt=txt; yyless(0); yyextra->offset+=yyextra->length; yyextra->istxt=0; *yylval=node; return TXT; } *(yyextra->boff+yyextra->depth)=0; /* previous node was a #for loop */ if(*(yyextra->nest+yyextra->depth-1)==RXV_SPIN_FOR){ *(yyextra->loop+yyextra->ldepth)=NULL; yyextra->ldepth--; } yyextra->offset+=yyleng; yyextra->col+=yyleng; yyextra->istxt=0; yyextra->depth--; if(yyextra->depth<0){ yyextra->error="minimum nesting depth exceeded"; return ERR; } yylval=NULL; return END; } . | "#f" | "#fo" | "#e" | "#en" | "#i" | "#u" | "#un" | "#unl" | "#unle" | "#unles" | "#el" | "#els" | \$[#@]* | \$[#@]*\{ | \$[#@]*\{[[:alpha:]] | \$[#@]*\{[[:alpha:]][[:alnum:]._-]* | [^$#\n]+ { if(!yyextra->istxt) /* start new text */ yyextra->length=0; yyextra->length+=yyleng; yyextra->col+=yyleng; yyextra->istxt=1; /* store the cached text */ if(yyextra->cacheall || yyextra->lengthbsizelength){ char *new; /* required size, plus up to the next step */ yyextra->bsize=(yyextra->length&~(RXV_SPIN_BUF_STEP-1))+RXV_SPIN_BUF_STEP; if(!(new=realloc(yyextra->buf,yyextra->bsize))){ yyextra->error="out of memory"; return ERR; } yyextra->buf=new; } memcpy(yyextra->buf+yyextra->length-yyleng,yytext,yyleng); } } "#f\n" | "#fo\n" | "#e\n" | "#en\n" | "#i\n" | "#u\n" | "#un\n" | "#unl\n" | "#unle\n" | "#unles\n" | "#el\n" | "#els\n" | \$[#@]*\n | \$[#@]*\{\n | \$[#@]*\{[[:alpha:]]\n | \$[#@]*\{[[:alpha:]][[:alnum:]._-]*\n | [^$#\n]+\n { if(!yyextra->istxt) /* start new text */ yyextra->length=0; yyextra->length+=yyleng; yyextra->row++; yyextra->col=0; yyextra->istxt=1; /* store the cached text */ if(yyextra->cacheall || yyextra->lengthbsizelength){ char *new; /* required size, plus up to the next step */ yyextra->bsize=(yyextra->length&~(RXV_SPIN_BUF_STEP-1))+RXV_SPIN_BUF_STEP; if(!(new=realloc(yyextra->buf,yyextra->bsize))){ yyextra->error="out of memory"; return ERR; } yyextra->buf=new; } memcpy(yyextra->buf+yyextra->length-yyleng,yytext,yyleng); } } \n+ { if(!yyextra->istxt) /* start new text */ yyextra->length=0; yyextra->length+=yyleng; yyextra->row+=yyleng; yyextra->col=0; yyextra->istxt=1; /* store the cached text */ if(yyextra->cacheall || yyextra->lengthbsizelength){ char *new; /* required size, plus up to the next step */ yyextra->bsize=(yyextra->length&~(RXV_SPIN_BUF_STEP-1))+RXV_SPIN_BUF_STEP; if(!(new=realloc(yyextra->buf,yyextra->bsize))){ yyextra->error="out of memory"; return ERR; } yyextra->buf=new; } memcpy(yyextra->buf+yyextra->length-yyleng,yytext,yyleng); } } /* command scanner */ { {REF} { size_t chunks,noff=2; int ldepth,loffset=0; char *p; rxv_spin_ref_t *ref; rxv_spin_node_t *node=apr_pcalloc(yyextra->pool,sizeof(*node)); if(!node){ yyextra->error="out of memory"; return ERR; } if(!(ref=apr_pcalloc(yyextra->tpool,sizeof(*ref)))){ yyextra->error="out of memory"; return ERR; } /* populate node */ node->type=RXV_SPIN_REF; node->ref=ref; if(*(yytext+1)=='#' || *(yytext+1)=='@') noff++; if(!(ref->name=apr_pstrmemdup(yyextra->tpool,yytext+noff,yyleng-(noff+1)))){ yyextra->error="out of memory"; return ERR; } /* count chunks of the name */ for(chunks=0,p=ref->name;p;p=strchr(p,'.')){ p++; chunks++; } /* find the last part of the reference name */ if((ref->chunk=strrchr(ref->name,'.'))){ if(!(ref->chunk=apr_pstrmemdup(yyextra->tpool,ref->chunk+1, strlen(ref->name)-(ref->chunk-ref->name)-1))){ yyextra->error="out of memory"; return ERR; } } else{ ref->chunk=ref->name; } /* was this a #for or an #if? */ if(*(yyextra->nest+yyextra->depth-1)==RXV_SPIN_FOR) loffset++; /* link the index of the nesting for loop */ for(ldepth=yyextra->ldepth-1-loffset;ldepth>=0 && !ref->loop;ldepth--){ char *name=(*(yyextra->loop+ldepth))->ref->name; size_t length=strlen(name); if(lengthname,length) && *(ref->name+length)=='.' && !strchr(ref->name+length+1,'.')) ref->loop=*(yyextra->loop+ldepth); } /* impossible loop reference, ignore the whole loop */ if(chunks>1 && !ref->loop) node=NULL; yyextra->offset+=yyleng; yyextra->col+=yyleng; /* link the reference to the #for loop */ if(loffset) (*(yyextra->loop+yyextra->ldepth-1))->ref=ref; *yylval=node; switch(*(yytext+1)){ case '#': ref->type=RXV_SPIN_REF_SIZ; break; case '@': ref->type=RXV_SPIN_REF_IND; break; default: ref->type=RXV_SPIN_REF_REG; break; } return CRF; } {REG} { rxv_spin_node_t *node=apr_pcalloc(yyextra->pool,sizeof(*node)); ap_regex_t *reg; char *sreg,*p,*r; if(!node){ yyextra->error="out of memory"; return ERR; } if(!(sreg=apr_pstrmemdup(yyextra->pool,yytext+1,yyleng-2))){ yyextra->error="out of memory"; return ERR; } /* populate node */ node->type=RXV_SPIN_REG; /* turn escaped '\/' into '/' */ for(p=sreg;*p;p++) if(*p=='\\' && *(p+1)=='/') for(r=p;r;r++) *r=*(r+1); if(!(reg=ap_pregcomp(yyextra->tpool,sreg,AP_REG_EXTENDED|AP_REG_NOSUB))){ yyextra->error="invalid regular expression"; return ERR; } /* finish populating the node */ node->reg=reg; yyextra->offset+=yyleng; yyextra->col+=yyleng; *yylval=node; return REG; } {LIT} { rxv_spin_node_t *node=apr_pcalloc(yyextra->pool,sizeof(*node)); char *lit,*p,*r; if(!node){ yyextra->error="out of memory"; return ERR; } if(!(lit=apr_pstrmemdup(yyextra->tpool,yytext+1,yyleng-2))){ yyextra->error="out of memory"; return ERR; } /* populate node */ node->type=RXV_SPIN_LIT; node->lit=lit; /* turn escaped '\"' into '"' */ for(p=lit;*p;p++) if(*p=='\\' && *(p+1)=='"') for(r=p;r;r++) *r=*(r+1); yyextra->offset+=yyleng; yyextra->col+=yyleng; *yylval=node; return LIT; } [[:digit:]]+ { rxv_spin_node_t *node=apr_pcalloc(yyextra->pool,sizeof(*node)); if(!node){ yyextra->error="out of memory"; return ERR; } /* populate node */ node->type=RXV_SPIN_NUM; node->num=atol(yytext); yyextra->offset+=yyleng; yyextra->col+=yyleng; *yylval=node; return NUM; } "(" { yyextra->offset++; yyextra->col++; yylval=NULL; return '('; } ")" { yyextra->offset++; yyextra->col++; yy_pop_state(yyscanner); yylval=NULL; return ')'; } "=~" { yyextra->offset+=yyleng; yyextra->col++; yylval=NULL; return MCH; } "==" { yyextra->offset+=yyleng; yyextra->col++; yylval=NULL; return EQL; } "%" { yyextra->offset++; yyextra->col++; yylval=NULL; return '%'; } [ \r\t]+ { /* ignore whitespace */ yyextra->offset+=yyleng; yyextra->col+=yyleng; } \n+ { /* ignore whitespace */ yyextra->offset+=yyleng; yyextra->row+=yyleng; yyextra->col=0; } =[^=~]* | \$[#@]* | \$[#@]*\{ | \$[#@]*\{[[:alpha:]] | \$[#@]*\{[[:alpha:]][[:alnum:]._-]* | \/([^/]|\\\/)* | \"([^"]|\\\")* | [^$()=%\"\/[:digit:]\n]+ { /* garbage */ yyextra->offset+=yyleng; yyextra->col+=yyleng; yyextra->error="garbage text in command"; yylval=NULL; return TXT; } } /* end of file handling */ <> { if(yyextra->istxt){ rxv_spin_node_t *node=apr_pcalloc(yyextra->tpool,sizeof(*node)); rxv_spin_txt_t *txt=apr_palloc(yyextra->tpool,sizeof(*txt)); if(!(node && txt)){ yyextra->error="out of memory"; return ERR; } txt->offset=yyextra->offset; txt->length=yyextra->length; /* pick up the cached text */ if(yyextra->cacheall || txt->lengthcache=apr_pmemdup(yyextra->tpool,yyextra->buf,txt->length))){ yyextra->error="out of memory"; return ERR; } } else{ txt->cache=NULL; } node->type=RXV_SPIN_TXT; node->txt=txt; yyless(0); yyextra->offset+=yyextra->length; yyextra->istxt=0; yyextra->iseof=1; *yylval=node; return TXT; } yyterminate(); } <> { yyterminate(); } %%