diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Makefile.am | 6 | ||||
-rw-r--r-- | common/expr.c | 207 | ||||
-rw-r--r-- | common/expr.h | 41 |
3 files changed, 252 insertions, 2 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index 1120b07..df90b8e 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -1,6 +1,6 @@ # Makefile.am - use automake to generate Makefile.in # -# Copyright (C) 2007, 2008 Arthur de Jong +# Copyright (C) 2007, 2008, 2009 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -17,7 +17,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA -noinst_LIBRARIES = libtio.a libprot.a libdict.a +noinst_LIBRARIES = libtio.a libprot.a libdict.a libexpr.a AM_CPPFLAGS=-I$(top_srcdir) AM_CFLAGS = -fPIC @@ -28,3 +28,5 @@ libprot_a_SOURCES = nslcd-prot.c nslcd-prot.h libdict_a_SOURCES = dict.c dict.h \ set.c set.h + +libexpr_a_SOURCES = expr.c expr.h diff --git a/common/expr.c b/common/expr.c new file mode 100644 index 0000000..679d8b7 --- /dev/null +++ b/common/expr.c @@ -0,0 +1,207 @@ +/* + expr.c - limited shell-like expression parsing functions + This file is part of the nss-pam-ldapd library. + + Copyright (C) 2009 Arthur de Jong + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> + +#include "expr.h" + +/* the maximum length of a variable name */ +#define MAXVARLENGTH 30 + +static inline int my_isalpha(const char c) +{ + return ((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z')); +} + +static inline int my_isalphanum(const char c) +{ + return my_isalpha(c)||((c>='0')&&(c<='9')); +} + +#include <stdio.h> + +/* return the part of the string that is a valid name */ +MUST_USE static const char *parse_name(const char *str,int *ptr,char *buffer,size_t buflen) +{ + int i=0; + /* clear the buffer */ + buffer[i]='\0'; + /* look for an alpha+alphanumeric* string */ + if (!my_isalpha(str[*ptr])) + return NULL; + while (my_isalphanum(str[*ptr])) + { + if ((size_t)i>=buflen) + return NULL; + buffer[i++]=str[(*ptr)++]; + } + /* NULL-terminate the string */ + if ((size_t)i>=buflen) + return NULL; + buffer[i++]='\0'; + return buffer; +} + +/* definition of the parse functions (they call eachother) */ +MUST_USE static const char *parse_dollar_expression( + const char *str,int *ptr,char *buffer,size_t buflen, + expander_t expander,void *expander_arg); +MUST_USE static const char *parse_expression( + const char *str,int *ptr,int endat,char *buffer,size_t buflen, + expander_t expander,void *expander_arg); + +MUST_USE static const char *parse_dollar_expression( + const char *str,int *ptr,char *buffer,size_t buflen, + expander_t expander,void *expander_arg) +{ + char varname[MAXVARLENGTH]; + const char *varvalue; + if ((buflen<=0)||(buffer==NULL)||(str==NULL)||(ptr==NULL)) + return NULL; + if (str[*ptr]=='{') + { + (*ptr)++; + /* the first part is always a variable name */ + if (parse_name(str,ptr,varname,sizeof(varname))==NULL) + return NULL; + varvalue=expander(varname,expander_arg); + if (str[*ptr]=='}') + { + /* simple substitute */ + if (strlen(varvalue)>=buflen) + return NULL; + strcpy(buffer,varvalue); + } + else if (strncmp(str+*ptr,":-",2)==0) + { + /* if variable is not set or empty, substitute remainder */ + (*ptr)+=2; + if (parse_expression(str,ptr,'}',buffer,buflen,expander,expander_arg)==NULL) + return NULL; + if ((varvalue!=NULL)&&(*varvalue!='\0')) + { + if (strlen(varvalue)>=buflen) + return NULL; + strcpy(buffer,varvalue); + } + } + else if (strncmp(str+*ptr,":+",2)==0) + { + /* if variable is set, substitute remainer */ + (*ptr)+=2; + if (parse_expression(str,ptr,'}',buffer,buflen,expander,expander_arg)==NULL) + return NULL; + if ((varvalue==NULL)||(*varvalue=='\0')) + buffer[0]='\0'; + } + else + return NULL; + (*ptr)++; /* skip closing } */ + } + else + { + /* it is a simple reference to a variable, like $uidNumber */ + if (parse_name(str,ptr,varname,sizeof(varname))==NULL) + return NULL; + varvalue=expander(varname,expander_arg); + if (strlen(varvalue)>=buflen) + return NULL; + strcpy(buffer,varvalue); + } + return buffer; +} + +MUST_USE static const char *parse_expression( + const char *str,int *ptr,int endat,char *buffer,size_t buflen, + expander_t expander,void *expander_arg) +{ + int j=0; + /* go over string */ + while ((str[*ptr]!=endat)&&(str[*ptr]!='\0')) + { + switch (str[*ptr]) + { + case '$': /* beginning of an expression */ + (*ptr)++; + if ((size_t)j>=buflen) + return NULL; + if (parse_dollar_expression(str,ptr,buffer+j,buflen-j,expander,expander_arg)==NULL) + return NULL; + j=strlen(buffer); + break; + case '\\': /* escaped character, unescape */ + (*ptr)++; + default: /* just copy the text */ + if ((size_t)j>=buflen) + return NULL; + buffer[j++]=str[*ptr]; + (*ptr)++; + } + } + /* NULL-terminate buffer */ + if ((size_t)j>=buflen) + return NULL; + buffer[j++]='\0'; + return buffer; +} + +MUST_USE const char *expr_parse(const char *str,char *buffer,size_t buflen, + expander_t expander,void *expander_arg) + +{ + int i=0; + return parse_expression(str,&i,'\0',buffer,buflen,expander,expander_arg); +} + +SET *expr_vars(const char *str,SET *set) +{ + char varname[MAXVARLENGTH]; + int i=0; + /* allocate set if needed */ + if (set==NULL) + set=set_new(); + if (set==NULL) + return NULL; + /* go over string */ + while (str[i]!='\0') + { + switch (str[i]) + { + case '$': /* beginning of a $-expression */ + i++; + if (str[i]=='{') + i++; + /* the rest should start with a variable name */ + if (parse_name(str,&i,varname,sizeof(varname))!=NULL) + set_add(set,varname); + break; + case '\\': /* escaped character, unescape */ + i++; + default: /* just skip */ + i++; + } + } + return set; +} diff --git a/common/expr.h b/common/expr.h new file mode 100644 index 0000000..9861a49 --- /dev/null +++ b/common/expr.h @@ -0,0 +1,41 @@ +/* + expr.h - limited shell-like expression parsing functions + This file is part of the nss-pam-ldapd library. + + Copyright (C) 2009 Arthur de Jong + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +#ifndef _EXPR_H +#define _EXPR_H 1 + +#include "compat/attrs.h" +#include "common/set.h" + +typedef const char *(*expander_t)(const char *name,void *expander_arg); + +/* Parse the expression and store the result in buffer, using the + expander function to expand variable names to values. If the expression + is invalid or the result didn't fit in the buffer NULL is returned. */ +MUST_USE const char *expr_parse(const char *expr,char *buffer,size_t buflen, + expander_t expander,void *expander_arg); + +/* Return the variable names that are used in expr. If set is NULL a new one + is allocated, otherwise the passed set is added to. */ +SET *expr_vars(const char *expr,SET *set); + +#endif /* not _EXPR_H */ |