Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Makefile.am6
-rw-r--r--common/expr.c207
-rw-r--r--common/expr.h41
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 */