Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorGiovanni Mascellani <mascellani@poisson.phc.unipi.it>2016-05-30 13:33:10 +0200
committerArthur de Jong <arthur@arthurdejong.org>2016-06-03 11:19:07 +0200
commit2ba95606dd95f68d423942b51e0e5b8d3d9ec145 (patch)
tree2bcf50013606e5d2d11bb2509fa30b6ead14bb71 /common
parent3a4860cd1d7175e7723307c31aeda68c24ef2309 (diff)
Support substituting expresions of type ${var:offset:length}
Diffstat (limited to 'common')
-rw-r--r--common/expr.c51
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 */