static int str_copy()

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;
}