/*
  RISC OS: helpers that MyODBC 3.51.30 takes from newer MySQL client
  libraries or the C library, for the mysql_3_23_58 / Acorn C build.
*/

#include "driver.h"
#include "stringutil.h"
#include <stdarg.h>

#if MYSQL_VERSION_ID < 40000

/* 3.23 has no mysql_autocommit(); 3.23 servers accept SET AUTOCOMMIT */
my_bool mysql_autocommit(MYSQL *mysql, my_bool auto_mode)
{
  return (my_bool) mysql_query(mysql, auto_mode ? "SET AUTOCOMMIT=1"
                                                : "SET AUTOCOMMIT=0");
}

/* net_realloc() is static in the 3.23 client; as MyODBC 3.51.06 did */
my_bool net_realloc(NET *net, ulong length)
{
  ulong pkt_length= (length + 8192) & ~(8192 - 1);
  uchar *buff;

  if (pkt_length > max_allowed_packet)
    return 1;
  if (!(buff= (uchar *) my_realloc((char *) net->buff, pkt_length,
                                   MYF(MY_WME))))
    return 1;
  net->buff= net->write_pos= buff;
  net->buff_end= buff + (net->max_packet= pkt_length);
  return 0;
}

char *strmake_root(MEM_ROOT *root, const char *str, unsigned int len)
{
  char *pos= alloc_root(root, len + 1);
  if (pos)
  {
    memcpy(pos, str, len);
    pos[len]= 0;
  }
  return pos;
}

/* As MySQL 5 mysys: wrap each argument in '...', with ' written as '\'' */
my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, ...)
{
  const char *quote_str= "\'";
  const unsigned int quote_len= 1;
  my_bool ret= TRUE;
  va_list dirty_text;

  ret&= dynstr_append_mem(str, quote_str, quote_len);
  va_start(dirty_text, append);
  while (append != NullS)
  {
    const char *cur_pos= append;
    const char *next_pos= cur_pos;

    while ((next_pos= strchr(cur_pos, '\'')) != NULL)
    {
      ret&= dynstr_append_mem(str, cur_pos, (uint) (next_pos - cur_pos));
      ret&= dynstr_append_mem(str, "\'\\\'\'", 4);
      cur_pos= next_pos + 1;
    }
    ret&= dynstr_append_mem(str, cur_pos, (uint) strlen(cur_pos));
    append= va_arg(dirty_text, char *);
  }
  va_end(dirty_text);
  ret&= dynstr_append_mem(str, quote_str, quote_len);

  return ret;
}

#endif /* MYSQL_VERSION_ID < 40000 */

#if MYSQL_VERSION_ID < 40100
/*
  The 3.23 client has no Unicode character sets, so the c.stringutil
  conversions are Latin-1 only: each byte is the code point of the same
  value, and characters above U+00FF become '?' (counted in errors).
*/

SQLWCHAR *sqlchar_as_sqlwchar(CHARSET_INFO *charset_info, SQLCHAR *str,
                              SQLINTEGER *len, uint *errors)
{
  SQLWCHAR *out;
  SQLINTEGER i;

  *errors= 0;
  if (*len == SQL_NTS)
    *len= str ? (SQLINTEGER) strlen((char *) str) : 0;
  if (!str || *len == 0)
  {
    *len= 0;
    return NULL;
  }
  if (!(out= (SQLWCHAR *) my_malloc(sizeof(SQLWCHAR) * (*len + 1), MYF(0))))
  {
    *len= -1;
    return NULL;
  }
  for (i= 0; i < *len; ++i)
    out[i]= (SQLWCHAR) str[i];
  out[i]= 0;
  return out;
}

SQLINTEGER sqlwchar_as_sqlchar_buf(CHARSET_INFO *charset_info,
                                   SQLCHAR *out, SQLINTEGER out_bytes,
                                   SQLWCHAR *str, SQLINTEGER len, uint *errors)
{
  SQLINTEGER i;

  *errors= 0;
  if (!str || out_bytes <= 0)
    return 0;
  if (len == SQL_NTS)
    len= (SQLINTEGER) sqlwcharlen(str);
  for (i= 0; i < len && i < out_bytes - 1; ++i)
  {
    if ((unsigned long) str[i] > 0xFF)
    {
      out[i]= '?';
      ++*errors;
    }
    else
      out[i]= (SQLCHAR) str[i];
  }
  out[i]= 0;
  return i;
}

SQLCHAR *sqlwchar_as_sqlchar(CHARSET_INFO *charset_info, SQLWCHAR *str,
                             SQLINTEGER *len, uint *errors)
{
  SQLCHAR *out;

  *errors= 0;
  if (*len == SQL_NTS)
    *len= str ? (SQLINTEGER) sqlwcharlen(str) : 0;
  if (!str || *len == 0)
  {
    *len= 0;
    return NULL;
  }
  if (!(out= (SQLCHAR *) my_malloc(*len + 1, MYF(0))))
  {
    *len= -1;
    return NULL;
  }
  *len= sqlwchar_as_sqlchar_buf(charset_info, out, *len + 1, str, *len,
                                errors);
  return out;
}

SQLCHAR *sqlchar_as_sqlchar(CHARSET_INFO *from_charset,
                            CHARSET_INFO *to_charset,
                            SQLCHAR *str, SQLINTEGER *len, uint *errors)
{
  SQLCHAR *out;

  *errors= 0;
  if (*len == SQL_NTS)
    *len= (SQLINTEGER) strlen((char *) str);
  if (!(out= (SQLCHAR *) my_malloc(*len + 1, MYF(0))))
  {
    *len= -1;
    return NULL;
  }
  memcpy(out, str, *len);
  out[*len]= 0;
  return out;
}

uint32
copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
                 const char *from, uint32 from_length, CHARSET_INFO *from_cs,
                 uint32 *used_bytes, uint32 *used_chars, uint *errors)
{
  uint32 length= to_length < from_length ? to_length : from_length;

  memcpy(to, from, length);
  if (used_bytes)
    *used_bytes= length;
  if (used_chars)
    *used_chars= length;
  if (errors)
    *errors= 0;
  return length;
}

#endif /* MYSQL_VERSION_ID < 40100 */

/* Single-tasking: localtime()'s static buffer is safe to copy from */
struct tm *localtime_r(const time_t *timep, struct tm *result)
{
  struct tm *tm= localtime(timep);
  if (!tm)
    return NULL;
  *result= *tm;
  return result;
}
