/*
 * Excerpted from https://sqlite.org/src/doc/tip/ext/misc/csv.c
 */

/* Skip leading whitespace.  Return a pointer to the first non-whitespace
** character, or to the zero terminator if the string has only whitespace */
static const char *csv_skip_whitespace(const char *z) {
  while (isspace((unsigned char)z[0]))
    z++;
  return z;
}

/* Remove trailing whitespace from the end of string z[] */
static void csv_trim_whitespace(char *z) {
  size_t n = strlen(z);
  while (n > 0 && isspace((unsigned char)z[n]))
    n--;
  z[n] = 0;
}

/* Dequote the string */
static void csv_dequote(char *z) {
  int j;
  char cQuote = z[0];
  size_t i, n;

  if (cQuote != '\'' && cQuote != '"')
    return;
  n = strlen(z);
  if (n < 2 || z[n - 1] != z[0])
    return;
  for (i = 1, j = 0; i < n - 1; i++) {
    if (z[i] == cQuote && z[i + 1] == cQuote)
      i++;
    z[j++] = z[i];
  }
  z[j] = 0;
}

/* Check to see if the string is of the form:  "TAG = VALUE" with optional
** whitespace before and around tokens.  If it is, return a pointer to the
** first character of VALUE.  If it is not, return NULL.
*/
static const char *csv_parameter(const char *zTag, int nTag, const char *z) {
  z = csv_skip_whitespace(z);
  if (strncmp(zTag, z, nTag) != 0)
    return 0;
  z = csv_skip_whitespace(z + nTag);
  if (z[0] != '=')
    return 0;
  return csv_skip_whitespace(z + 1);
}

/* Decode a parameter that requires a dequoted string.
**
** Return 1 if the parameter is seen, or 0 if not.  1 is returned
** even if there is an error.  If an error occurs, then an error message
** is left in p->zErr.  If there are no errors, p->zErr[0]==0.
*/
static int csv_string_parameter(char **errmsg,      /* Leave the error message here, if there is one */
                                const char *zParam, /* Parameter we are checking for */
                                const char *zArg,   /* Raw text of the virtual table argment */
                                char **pzVal        /* Write the dequoted string value here */
) {
  const char *zValue;
  if (!zParam) {
    asprintf(errmsg, "unrecognized connection parameter: %s", zArg);
    return 1;
  }
  zValue = csv_parameter(zParam, (int)strlen(zParam), zArg);
  if (zValue == 0)
    return 0;
  if (*pzVal) {
    asprintf(errmsg, "more than one '%s' parameter", zParam);
    return 1;
  }
  *pzVal = sqlite3_mprintf("%s", zValue);
  if (*pzVal == 0) {
    asprintf(errmsg, "out of memory");
    return 1;
  }
  csv_trim_whitespace(*pzVal);
  csv_dequote(*pzVal);
  return 1;
}
