diff options
author | Giovanni Mascellani <mascellani@poisson.phc.unipi.it> | 2016-05-30 13:33:10 +0200 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2016-06-03 11:19:07 +0200 |
commit | 2ba95606dd95f68d423942b51e0e5b8d3d9ec145 (patch) | |
tree | 2bcf50013606e5d2d11bb2509fa30b6ead14bb71 /common | |
parent | 3a4860cd1d7175e7723307c31aeda68c24ef2309 (diff) |
Support substituting expresions of type ${var:offset:length}
Diffstat (limited to 'common')
-rw-r--r-- | common/expr.c | 51 |
1 files changed, 51 insertions, 0 deletions
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 <t.glaser@tarent.de> + Copyright (c) 2016 Giovanni Mascellani <gio@debian.org> 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 <stdlib.h> #include <string.h> #include <stdio.h> +#include <errno.h> #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 */ |