in Sources/CCryptoBoringSSL/crypto/conf/conf.c [214:378]
static int str_copy(CONF *conf, char *section, char **pto, char *from) {
int q, r, rr = 0, to = 0, len = 0;
char *s, *e, *rp, *rrp, *np, *cp, v;
const char *p;
BUF_MEM *buf;
buf = BUF_MEM_new();
if (buf == NULL) {
return 0;
}
len = strlen(from) + 1;
if (!BUF_MEM_grow(buf, len)) {
goto err;
}
for (;;) {
if (IS_QUOTE(conf, *from)) {
q = *from;
from++;
while (!IS_EOF(conf, *from) && (*from != q)) {
if (IS_ESC(conf, *from)) {
from++;
if (IS_EOF(conf, *from)) {
break;
}
}
buf->data[to++] = *(from++);
}
if (*from == q) {
from++;
}
} else if (IS_DQUOTE(conf, *from)) {
q = *from;
from++;
while (!IS_EOF(conf, *from)) {
if (*from == q) {
if (*(from + 1) == q) {
from++;
} else {
break;
}
}
buf->data[to++] = *(from++);
}
if (*from == q) {
from++;
}
} else if (IS_ESC(conf, *from)) {
from++;
v = *(from++);
if (IS_EOF(conf, v)) {
break;
} else if (v == 'r') {
v = '\r';
} else if (v == 'n') {
v = '\n';
} else if (v == 'b') {
v = '\b';
} else if (v == 't') {
v = '\t';
}
buf->data[to++] = v;
} else if (IS_EOF(conf, *from)) {
break;
} else if (*from == '$') {
// try to expand it
rrp = NULL;
s = &(from[1]);
if (*s == '{') {
q = '}';
} else if (*s == '(') {
q = ')';
} else {
q = 0;
}
if (q) {
s++;
}
cp = section;
e = np = s;
while (IS_ALPHA_NUMERIC(conf, *e)) {
e++;
}
if (e[0] == ':' && e[1] == ':') {
cp = np;
rrp = e;
rr = *e;
*rrp = '\0';
e += 2;
np = e;
while (IS_ALPHA_NUMERIC(conf, *e)) {
e++;
}
}
r = *e;
*e = '\0';
rp = e;
if (q) {
if (r != q) {
OPENSSL_PUT_ERROR(CONF, CONF_R_NO_CLOSE_BRACE);
goto err;
}
e++;
}
// So at this point we have
// np which is the start of the name string which is
// '\0' terminated.
// cp which is the start of the section string which is
// '\0' terminated.
// e is the 'next point after'.
// r and rr are the chars replaced by the '\0'
// rp and rrp is where 'r' and 'rr' came from.
p = NCONF_get_string(conf, cp, np);
if (rrp != NULL) {
*rrp = rr;
}
*rp = r;
if (p == NULL) {
OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_HAS_NO_VALUE);
goto err;
}
size_t newsize = strlen(p) + buf->length - (e - from);
if (newsize > MAX_CONF_VALUE_LENGTH) {
OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_EXPANSION_TOO_LONG);
goto err;
}
if (!BUF_MEM_grow_clean(buf, newsize)) {
OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
goto err;
}
while (*p) {
buf->data[to++] = *(p++);
}
/* Since we change the pointer 'from', we also have
to change the perceived length of the string it
points at. /RL */
len -= e - from;
from = e;
/* In case there were no braces or parenthesis around
the variable reference, we have to put back the
character that was replaced with a '\0'. /RL */
*rp = r;
} else {
buf->data[to++] = *(from++);
}
}
buf->data[to] = '\0';
if (*pto != NULL) {
OPENSSL_free(*pto);
}
*pto = buf->data;
OPENSSL_free(buf);
return 1;
err:
if (buf != NULL) {
BUF_MEM_free(buf);
}
return 0;
}