From 2ba95606dd95f68d423942b51e0e5b8d3d9ec145 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 30 May 2016 13:33:10 +0200 Subject: Support substituting expresions of type ${var:offset:length} --- common/expr.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'common') diff --git a/common/expr.c b/common/expr.c index 2b12e74..a5691b5 100644 --- a/common/expr.c +++ b/common/expr.c @@ -4,6 +4,7 @@ Copyright (C) 2009-2016 Arthur de Jong Copyright (c) 2012 Thorsten Glaser + Copyright (c) 2016 Giovanni Mascellani This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -26,6 +27,7 @@ #include #include #include +#include #include "expr.h" #include "compat/attrs.h" @@ -38,6 +40,11 @@ static inline int my_isalpha(const char c) return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); } +static inline int my_isdigit(const char c) +{ + return (c >= '0') && (c <= '9'); +} + static inline int my_isalphanum(const char c) { return my_isalpha(c) || ((c >= '0') && (c <= '9')); @@ -127,6 +134,43 @@ MUST_USE static const char *parse_dollar_alternative( return buffer; } +/* handle ${attr:offset:length} expressions */ +MUST_USE static const char *parse_dollar_substring( + const char *str, int *ptr, char *buffer, size_t buflen, + const char *varvalue) +{ + char *tmp; + unsigned long int offset, length; + size_t varlen; + /* parse input */ + tmp = (char *)str + *ptr; + if (!my_isdigit(*tmp)) + return NULL; + errno = 0; + offset = strtoul(tmp, &tmp, 10); + if ((*tmp != ':') || (errno != 0)) + return NULL; + tmp += 1; + errno = 0; + length = strtoul(tmp, &tmp, 10); + if ((*tmp != '}') || (errno != 0)) + return NULL; + /* don't skip closing '}' here, because it will be skipped later */ + *ptr += tmp - (str + *ptr); + varlen = strlen(varvalue); + if (offset > varlen) + offset = varlen; + if (offset + length > varlen) + length = varlen - offset; + if (length >= buflen) + return NULL; + /* everything's ok, copy data; we use memcpy instead of strncpy + because we already know the exact lenght in play */ + memcpy(buffer, varvalue + offset, length); + buffer[length] = '\0'; + return buffer; +} + /* handle ${attr#word} expressions */ MUST_USE static const char *parse_dollar_match( const char *str, int *ptr, char *buffer, size_t buflen, @@ -212,6 +256,13 @@ MUST_USE static const char *parse_dollar_expression( if (parse_dollar_alternative(str, ptr, buffer, buflen, expander, expander_arg, varvalue) == NULL) return NULL; } + else if (str[*ptr] == ':') + { + /* substitute substring of variable */ + (*ptr) += 1; + if (parse_dollar_substring(str, ptr, buffer, buflen, varvalue) == NULL) + return NULL; + } else if (str[*ptr] == '#') { /* try to strip the remainder value from variable beginning */ -- cgit v1.2.3