Ejemplo n.º 1
0
static my_bool init_state_maps(CHARSET_INFO *cs)
{
  uint i;
  uchar *state_map;
  uchar *ident_map;

  if (!(cs->state_map= state_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
    return 1;

  if (!(cs->ident_map= ident_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
    return 1;

  /* Fill state_map with states to get a faster parser */
  for (i=0; i < 256 ; i++)
  {
    if (my_isalpha(cs,i))
      state_map[i]=(uchar) MY_LEX_IDENT;
    else if (my_isdigit(cs,i))
      state_map[i]=(uchar) MY_LEX_NUMBER_IDENT;
    else if (my_ismb1st(cs, i))
      /* To get whether it's a possible leading byte for a charset. */
      state_map[i]=(uchar) MY_LEX_IDENT;
    else if (my_isspace(cs,i))
      state_map[i]=(uchar) MY_LEX_SKIP;
    else
      state_map[i]=(uchar) MY_LEX_CHAR;
  }
  state_map[(uchar)'_']=state_map[(uchar)'$']=(uchar) MY_LEX_IDENT;
  state_map[(uchar)'\'']=(uchar) MY_LEX_STRING;
  state_map[(uchar)'.']=(uchar) MY_LEX_REAL_OR_POINT;
  state_map[(uchar)'>']=state_map[(uchar)'=']=state_map[(uchar)'!']= (uchar) MY_LEX_CMP_OP;
  state_map[(uchar)'<']= (uchar) MY_LEX_LONG_CMP_OP;
  state_map[(uchar)'&']=state_map[(uchar)'|']=(uchar) MY_LEX_BOOL;
  state_map[(uchar)'#']=(uchar) MY_LEX_COMMENT;
  state_map[(uchar)';']=(uchar) MY_LEX_SEMICOLON;
  state_map[(uchar)':']=(uchar) MY_LEX_SET_VAR;
  state_map[0]=(uchar) MY_LEX_EOL;
  state_map[(uchar)'\\']= (uchar) MY_LEX_ESCAPE;
  state_map[(uchar)'/']= (uchar) MY_LEX_LONG_COMMENT;
  state_map[(uchar)'*']= (uchar) MY_LEX_END_LONG_COMMENT;
  state_map[(uchar)'@']= (uchar) MY_LEX_USER_END;
  state_map[(uchar) '`']= (uchar) MY_LEX_USER_VARIABLE_DELIMITER;
  state_map[(uchar)'"']= (uchar) MY_LEX_STRING_OR_DELIMITER;

  /*
    Create a second map to make it faster to find identifiers
  */
  for (i=0; i < 256 ; i++)
  {
    ident_map[i]= (uchar) (state_map[i] == MY_LEX_IDENT ||
			   state_map[i] == MY_LEX_NUMBER_IDENT);
  }

  /* Special handling of hex and binary strings */
  state_map[(uchar)'x']= state_map[(uchar)'X']= (uchar) MY_LEX_IDENT_OR_HEX;
  state_map[(uchar)'b']= state_map[(uchar)'B']= (uchar) MY_LEX_IDENT_OR_BIN;
  state_map[(uchar)'n']= state_map[(uchar)'N']= (uchar) MY_LEX_IDENT_OR_NCHAR;

  return 0;
}
Ejemplo n.º 2
0
/* behave like scanf("%d", &i) */
int read_int(char *w)
{
    int i, ch;
    w[0] = '0';
    //int intVal = 0, s = 1;
    
    /* till new line is reached, collect the characters 
     * in s whose reference is passed 
     */
	
    for (i=0; ((ch = getchar()) != '\n'); i++)
    {
        /* check for negative value */
        if ( ch == '-')
        {
            /* If first digit is -, let s = 1 and start i from next */
            //s = -1;
            w[0] = '-';
            i++;
            ch = getchar();
        }
        
		if(my_isdigit(ch))
		{
			w[i] = ch;
            //intVal = intVal*10 + ch - '0';
		}
		
    }
    //printf("%d\n", (s * intVal));
    return 0 ;
}
Ejemplo n.º 3
0
static int	my_atoi_isvalid(const char *s, int i)
{
  if (my_isdigit(s[i]) == 1
      || (i == 0 && (s[i] == '-' || s[i] == '+')))
    return (1);
  return (0);
}
Ejemplo n.º 4
0
void my_regex_init(CHARSET_INFO *cs, my_regex_stack_check_t func)
{
  char buff[CCLASS_LAST][256];
  int  count[CCLASS_LAST];
  uint i;

  if (!regex_inited)
  {
    regex_inited=1;
    my_regex_enough_mem_in_stack= func;
    bzero((uchar*) &count,sizeof(count));

    for (i=1 ; i<= 255; i++)
    {
      if (my_isalnum(cs,i))
	buff[CCLASS_ALNUM][count[CCLASS_ALNUM]++]=(char) i;
      if (my_isalpha(cs,i))
	buff[CCLASS_ALPHA][count[CCLASS_ALPHA]++]=(char) i;
      if (my_iscntrl(cs,i))
	buff[CCLASS_CNTRL][count[CCLASS_CNTRL]++]=(char) i;
      if (my_isdigit(cs,i))
	buff[CCLASS_DIGIT][count[CCLASS_DIGIT]++]=(char) i;
      if (my_isgraph(cs,i))
	buff[CCLASS_GRAPH][count[CCLASS_GRAPH]++]=(char) i;
      if (my_islower(cs,i))
	buff[CCLASS_LOWER][count[CCLASS_LOWER]++]=(char) i;
      if (my_isprint(cs,i))
	buff[CCLASS_PRINT][count[CCLASS_PRINT]++]=(char) i;
      if (my_ispunct(cs,i))
	buff[CCLASS_PUNCT][count[CCLASS_PUNCT]++]=(char) i;
      if (my_isspace(cs,i))
	buff[CCLASS_SPACE][count[CCLASS_SPACE]++]=(char) i;
      if (my_isupper(cs,i))
	buff[CCLASS_UPPER][count[CCLASS_UPPER]++]=(char) i;
      if (my_isxdigit(cs,i))
	buff[CCLASS_XDIGIT][count[CCLASS_XDIGIT]++]=(char) i;
    }
    buff[CCLASS_BLANK][0]=' ';
    buff[CCLASS_BLANK][1]='\t';
    count[CCLASS_BLANK]=2;
    for (i=0; i < CCLASS_LAST ; i++)
    {
      char *tmp=(char*) malloc(count[i]+1);
      if (!tmp)
      {
	/*
	  This is very unlikely to happen as this function is called once
	  at program startup
	*/
	fprintf(stderr,
		"Fatal error: Can't allocate memory in regex_init\n");
	exit(1);
      }
      memcpy(tmp,buff[i],count[i]*sizeof(char));
      tmp[count[i]]=0;
      cclasses[i].chars=tmp;
    }
  }
  return;
}
Ejemplo n.º 5
0
static uint skip_digits(const char **str, const char *end)
{
  const char *start= *str, *s= *str;
  while (s < end && my_isdigit(&my_charset_latin1, *s))
    s++;
  *str= s;
  return s - start;
}
Ejemplo n.º 6
0
/*
** Note that the function check the passed char for presence in the base, if
** so, the function shall consider it as a number and won't ignore it.
*/
int	my_isspace(char c, char *base)
{
  if (my_isdigit(c, base))
    return (0);
  if (c == ' ')
    return (1);
  return (0);
}
Ejemplo n.º 7
0
static const char *get_width(const char *fmt, size_t *width)
{
  for (; my_isdigit(&my_charset_latin1, *fmt); fmt++)
  {
    *width= *width * 10 + (uint)(*fmt - '0');
  }
  return fmt;
}
Ejemplo n.º 8
0
static int get_number(uint *val, uint *number_of_fields, const char **str,
                      const char *end)
{
  const char *s = *str;

  if (s >= end)
    return 0;

  if (!my_isdigit(&my_charset_latin1, *s))
    return 1;
  *val= *s++ - '0';

  for (; s < end && my_isdigit(&my_charset_latin1, *s); s++)
    *val= *val * 10 + *s - '0';
  *str = s;
  (*number_of_fields)++;
  return 0;
}
Ejemplo n.º 9
0
static const char *get_length(const char *fmt, size_t *length, uint *pre_zero)
{
  for (; my_isdigit(&my_charset_latin1, *fmt); fmt++)
  {
    *length= *length * 10 + (uint)(*fmt - '0');
    if (!*length)
      *pre_zero|= PREZERO_ARG;                  /* first digit was 0 */
  }
  return fmt;
}
Ejemplo n.º 10
0
int main()
{
  static char test_chars[] = { 'a', '5', ' ', '\n', 48, '\t', 'G', '!' };
  int i;
  static char *result;

  for (i = 0; i < sizeof(test_chars); i++) {
    if (my_isdigit(test_chars[i]))
       result = "yes";
    else
       result = "no";
   printf("%c %s\n", test_chars[i], result);
  }
}
Ejemplo n.º 11
0
static const char *
trailing_digits (const char *p)
{
  const char *end;

  end = p + strlen(p) - 1;
  while (end >= p)
    {
      if (! my_isdigit(*end))
	break;
      end--;
    }

  return end + 1;
}
Ejemplo n.º 12
0
/**************************************************************************
 Verifies that a password is valid. Does some [very] rudimentary safety 
 checks. TODO: do we want to frown on non-printing characters?
 Fill the msg (length MAX_LEN_MSG) with any worthwhile information that 
 the client ought to know. 
**************************************************************************/
static bool is_good_password(const char *password, char *msg)
{
  int i, num_caps = 0, num_nums = 0;
   
  /* check password length */
  if (strlen(password) < MIN_PASSWORD_LEN) {
    my_snprintf(msg, MAX_LEN_MSG,
                _("Your password is too short, the minimum length is %d. "
                  "Try again."), MIN_PASSWORD_LEN);
    return FALSE;
  }
 
  my_snprintf(msg, MAX_LEN_MSG,
              _("The password must have at least %d capital letters, %d "
                "numbers, and be at minimum %d [printable] characters long. "
                "Try again."), 
              MIN_PASSWORD_CAPS, MIN_PASSWORD_NUMS, MIN_PASSWORD_LEN);

  for (i = 0; i < strlen(password); i++) {
    if (my_isupper(password[i])) {
      num_caps++;
    }
    if (my_isdigit(password[i])) {
      num_nums++;
    }
  }

  /* check number of capital letters */
  if (num_caps < MIN_PASSWORD_CAPS) {
    return FALSE;
  }

  /* check number of numbers */
  if (num_nums < MIN_PASSWORD_NUMS) {
    return FALSE;
  }

  if (!is_ascii_name(password)) {
    return FALSE;
  }

  return TRUE;
}
Ejemplo n.º 13
0
static unsigned long my_atou_x(char *s)
{
	unsigned radix=10, c;
	unsigned long n=0;

	while (*s == ' ' || *s == '\t') s++;

	if (s[0] == '0' && s[1] == 'x') {
		radix = 16;
		s += 2;
	}

	while (my_isalnum(*s)) {
		c = my_tolower(*s); s++;
		if (my_isdigit(c)) c=c-'0'; else c=c-'A'+10;
		if (c >= radix) break;
		n = n * radix + c;
	}

	return n;
}
Ejemplo n.º 14
0
int main()
{
  
       char givenCharacter;
       char option;
    do
    {
        /* Read a character from user */
        printf("Enter a character: ");
        scanf("\n%c", &givenCharacter);
        
        /* Test for int my_isalpha(int var) function by passing givenCharacter */
        my_isalpha(givenCharacter) ? printf("my_isalpha: Success\n"):printf("my_isalpha: Failed\n");
    
        /* Test for int my_isalnum(int var) function by passing givenCharacter */
        my_isalnum(givenCharacter) ? printf("my_isalnum: Success\n"):printf("my_isalnum: Failed\n");
        
        /* Test for int my_isxdigit(int var) function by passing givenCharacter */
        my_isdigit(givenCharacter) ? printf("my_isdigit: Success\n"):printf("my_isdigit: Failed\n");
        
        /* Test for int my_iscntrl(int var) function by passing givenCharacter */
        my_iscntrl(givenCharacter) ? printf("my_iscntrl: Success\n"):printf("my_iscntrl: Failed\n");
       
       /* Prompt for Continue option */
       printf("Continue (y/n): ");
       scanf("\n%c", &option);
       
       if ( option == 'y' )
       {
           continue;
       }
       else
       {
           break;
       }
   } while (1);
    
	return 0;
}
Ejemplo n.º 15
0
int     my_getnbr(char *str)
{
  int   i;
  int   nb;
  int   neg;

  i = 0;
  neg = 0;
  while (str[i])
    {
      if (str[i] == '-')
        neg++;
      else if (!my_isdigit(str[i]))
	return (-1);
      else if (str[i] >= '0' && str[i] <= '9')
        {
          nb = get_number(str, i, neg);
          return (nb);
        }
      i++;
    }
  return (0);
}
Ejemplo n.º 16
0
int		my_atoi(const char *s)
{
  int		i;
  int		sign;
  int		result;

  if (!s)
    return (0);
  i = 0;
  sign = 1;
  result = 0;
  while (my_isspace(*s) == 1)
    s++;
  while (s[i] != '\0' && my_atoi_isvalid(s, i) == 1)
    {
      if (i == 0 && s[i] == '-')
	sign = -1;
      if (my_isdigit(s[i]))
	result = s[i] - '0' + result * 10;
      i += 1;
    }
  return (result * sign);
}
Ejemplo n.º 17
0
double my_strtod(const char *str, char **end_ptr, int *error)
{
  double result= 0.0;
  uint negative= 0, ndigits, dec_digits= 0, neg_exp= 0;
  int exp= 0, digits_after_dec_point= 0;
  const char *old_str, *end= *end_ptr, *start_of_number;
  char next_char;
  my_bool overflow=0;

  *error= 0;
  if (str >= end)
    goto done;

  while (my_isspace(&my_charset_latin1, *str))
  {
    if (++str == end)
      goto done;
  }

  start_of_number= str;
  if ((negative= (*str == '-')) || *str=='+')
  {
    if (++str == end)
      goto done;                                /* Could be changed to error */
  }

  /* Skip pre-zero for easier calculation of overflows */
  while (*str == '0')
  {
    if (++str == end)
      goto done;
    start_of_number= 0;                         /* Found digit */
  }

  old_str= str;
  while ((next_char= *str) >= '0' && next_char <= '9')
  {
    result= result*10.0 + (next_char - '0');
    if (++str == end)
    {
      next_char= 0;                             /* Found end of string */
      break;
    }
    start_of_number= 0;                         /* Found digit */
  }
  ndigits= (uint) (str-old_str);

  if (next_char == '.' && str < end-1)
  {
    /*
      Continue to add numbers after decimal point to the result, as if there
      was no decimal point. We will later (in the exponent handling) shift
      the number down with the required number of fractions.  We do it this
      way to be able to get maximum precision for numbers like 123.45E+02,
      which are normal for some ODBC applications.
    */
    old_str= ++str;
    while (my_isdigit(&my_charset_latin1, (next_char= *str)))
    {
      result= result*10.0 + (next_char - '0');
      digits_after_dec_point++;
      if (++str == end)
      {
        next_char= 0;
        break;
      }
    }
    /* If we found just '+.' or '.' then point at first character */
    if (!(dec_digits= (uint) (str-old_str)) && start_of_number)
      str= start_of_number;                     /* Point at '+' or '.' */
  }
  if ((next_char == 'e' || next_char == 'E') &&
      dec_digits + ndigits != 0 && str < end-1)
  {
    const char *old_str= str++;

    if ((neg_exp= (*str == '-')) || *str == '+')
      str++;

    if (str == end || !my_isdigit(&my_charset_latin1, *str))
      str= old_str;
    else
    {
      do
      {
        if (exp < 9999)                         /* prot. against exp overfl. */
          exp= exp*10 + (*str - '0');
        str++;
      } while (str < end && my_isdigit(&my_charset_latin1, *str));
    }
  }
  if ((exp= (neg_exp ? exp + digits_after_dec_point :
             exp - digits_after_dec_point)))
  {
    double scaler;
    if (exp < 0)
    {
      exp= -exp;
      neg_exp= 1;                               /* neg_exp was 0 before */
    }
    if (exp + ndigits >= MAX_DBL_EXP + 1 && result)
    {
      /*
        This is not 100 % as we actually will give an owerflow for
        17E307 but not for 1.7E308 but lets cut some corners to make life
        simpler
      */
      if (exp + ndigits > MAX_DBL_EXP + 1 ||
          result >= MAX_RESULT_FOR_MAX_EXP)
      {
        if (neg_exp)
          result= 0.0;
        else
          overflow= 1;
        goto done;
      }
    }
    scaler= 1.0;
    while (exp >= 100)
    {
      scaler*= 1.0e100;
      exp-= 100;
    }
    scaler*= scaler10[exp/10]*scaler1[exp%10];
    if (neg_exp)
      result/= scaler;
    else
      result*= scaler;
  }

done:
  *end_ptr= (char*) str;                        /* end of number */

  if (overflow || isinf(result))
  {
    result= DBL_MAX;
    *error= EOVERFLOW;
  }

  return negative ? -result : result;
}
Ejemplo n.º 18
0
my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
                    int *warning)
{
  ulong date[5];
  ulonglong value;
  const char *end=str+length, *end_of_days;
  my_bool found_days,found_hours;
  uint state;

  l_time->neg=0;
  *warning= 0;
  for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++)
    length--;
  if (str != end && *str == '-')
  {
    l_time->neg=1;
    str++;
    length--;
  }
  if (str == end)
    return 1;

  /* Check first if this is a full TIMESTAMP */
  if (length >= 12)
  {                                             /* Probably full timestamp */
    int was_cut;
    enum enum_mysql_timestamp_type
      res= str_to_datetime(str, length, l_time,
                           (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), &was_cut);
    if ((int) res >= (int) MYSQL_TIMESTAMP_ERROR)
    {
      if (was_cut)
        *warning|= MYSQL_TIME_WARN_TRUNCATED;
      return res == MYSQL_TIMESTAMP_ERROR;
    }
  }

  /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
  for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
    value=value*10L + (long) (*str - '0');

  /* Skip all space after 'days' */
  end_of_days= str;
  for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++)
    ;

  LINT_INIT(state);
  found_days=found_hours=0;
  if ((uint) (end-str) > 1 && str != end_of_days &&
      my_isdigit(&my_charset_latin1, *str))
  {                                             /* Found days part */
    date[0]= (ulong) value;
    state= 1;                                   /* Assume next is hours */
    found_days= 1;
  }
  else if ((end-str) > 1 &&  *str == time_separator &&
           my_isdigit(&my_charset_latin1, str[1]))
  {
    date[0]= 0;                                 /* Assume we found hours */
    date[1]= (ulong) value;
    state=2;
    found_hours=1;
    str++;                                      /* skip ':' */
  }
  else
  {
    /* String given as one number; assume HHMMSS format */
    date[0]= 0;
    date[1]= (ulong) (value/10000);
    date[2]= (ulong) (value/100 % 100);
    date[3]= (ulong) (value % 100);
    state=4;
    goto fractional;
  }

  /* Read hours, minutes and seconds */
  for (;;)
  {
    for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
      value=value*10L + (long) (*str - '0');
    date[state++]= (ulong) value;
    if (state == 4 || (end-str) < 2 || *str != time_separator ||
        !my_isdigit(&my_charset_latin1,str[1]))
      break;
    str++;                                      /* Skip time_separator (':') */
  }

  if (state != 4)
  {                                             /* Not HH:MM:SS */
    /* Fix the date to assume that seconds was given */
    if (!found_hours && !found_days)
    {
      bmove_upp((uchar*) (date+4), (uchar*) (date+state),
                sizeof(long)*(state-1));
      bzero((uchar*) date, sizeof(long)*(4-state));
    }
    else
      bzero((uchar*) (date+state), sizeof(long)*(4-state));
  }

fractional:
  /* Get fractional second part */
  if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1]))
  {
    int field_length= 5;
    str++; value=(uint) (uchar) (*str - '0');
    while (++str != end && my_isdigit(&my_charset_latin1, *str))
    {
      if (field_length-- > 0)
        value= value*10 + (uint) (uchar) (*str - '0');
    }
    if (field_length > 0)
      value*= (long) log_10_int[field_length];
    else if (field_length < 0)
      *warning|= MYSQL_TIME_WARN_TRUNCATED;
    date[4]= (ulong) value;
  }
  else
    date[4]=0;
    
  /* Check for exponent part: E<gigit> | E<sign><digit> */
  /* (may occur as result of %g formatting of time value) */
  if ((end - str) > 1 &&
      (*str == 'e' || *str == 'E') &&
      (my_isdigit(&my_charset_latin1, str[1]) ||
       ((str[1] == '-' || str[1] == '+') &&
        (end - str) > 2 &&
        my_isdigit(&my_charset_latin1, str[2]))))
    return 1;

  if (internal_format_positions[7] != 255)
  {
    /* Read a possible AM/PM */
    while (str != end && my_isspace(&my_charset_latin1, *str))
      str++;
    if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
    {
      if (str[0] == 'p' || str[0] == 'P')
      {
        str+= 2;
        date[1]= date[1]%12 + 12;
      }
      else if (str[0] == 'a' || str[0] == 'A')
        str+=2;
    }
  }

  /* Integer overflow checks */
  if (date[0] > UINT_MAX || date[1] > UINT_MAX ||
      date[2] > UINT_MAX || date[3] > UINT_MAX ||
      date[4] > UINT_MAX)
    return 1;
  
  l_time->year=         0;                      /* For protocol::store_time */
  l_time->month=        0;
  l_time->day=          date[0];
  l_time->hour=         date[1];
  l_time->minute=       date[2];
  l_time->second=       date[3];
  l_time->second_part=  date[4];
  l_time->time_type= MYSQL_TIMESTAMP_TIME;

  /* Check if the value is valid and fits into MYSQL_TIME range */
  if (check_time_range(l_time, warning))
    return 1;
  
  /* Check if there is garbage at end of the MYSQL_TIME specification */
  if (str != end)
  {
    do
    {
      if (!my_isspace(&my_charset_latin1,*str))
      {
        *warning|= MYSQL_TIME_WARN_TRUNCATED;
        break;
      }
    } while (++str != end);
  }
  return 0;
}
Ejemplo n.º 19
0
enum enum_mysql_timestamp_type
str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
                ulonglong flags, int *was_cut)
{
  uint field_length, UNINIT_VAR(year_length), digits, i, number_of_fields;
  uint date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS];
  uint add_hours= 0, start_loop;
  ulong not_zero_date, allow_space;
  my_bool is_internal_format;
  const char *pos, *UNINIT_VAR(last_field_pos);
  const char *end=str+length;
  const uchar *format_position;
  my_bool found_delimitier= 0, found_space= 0;
  uint frac_pos, frac_len;
  DBUG_ENTER("str_to_datetime");
  DBUG_PRINT("ENTER",("str: %.*s",length,str));

  LINT_INIT(field_length);

  *was_cut= 0;

  /* Skip space at start */
  for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++)
    ;
  if (str == end || ! my_isdigit(&my_charset_latin1, *str))
  {
    *was_cut= 1;
    DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
  }

  is_internal_format= 0;
  /* This has to be changed if want to activate different timestamp formats */
  format_position= internal_format_positions;

  /*
    Calculate number of digits in first part.
    If length= 8 or >= 14 then year is of format YYYY.
    (YYYY-MM-DD,  YYYYMMDD, YYYYYMMDDHHMMSS)
  */
  for (pos=str;
       pos != end && (my_isdigit(&my_charset_latin1,*pos) || *pos == 'T');
       pos++)
    ;

  digits= (uint) (pos-str);
  start_loop= 0;                                /* Start of scan loop */
  date_len[format_position[0]]= 0;              /* Length of year field */
  if (pos == end || *pos == '.')
  {
    /* Found date in internal format (only numbers like YYYYMMDD) */
    year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
    field_length= year_length;
    is_internal_format= 1;
    format_position= internal_format_positions;
  }
  else
  {
    if (format_position[0] >= 3)                /* If year is after HHMMDD */
    {
      /*
        If year is not in first part then we have to determinate if we got
        a date field or a datetime field.
        We do this by checking if there is two numbers separated by
        space in the input.
      */
      while (pos < end && !my_isspace(&my_charset_latin1, *pos))
        pos++;
      while (pos < end && !my_isdigit(&my_charset_latin1, *pos))
        pos++;
      if (pos == end)
      {
        if (flags & TIME_DATETIME_ONLY)
        {
          *was_cut= 1;
          DBUG_RETURN(MYSQL_TIMESTAMP_NONE);   /* Can't be a full datetime */
        }
        /* Date field.  Set hour, minutes and seconds to 0 */
        date[0]= date[1]= date[2]= date[3]= date[4]= 0;
        start_loop= 5;                         /* Start with first date part */
      }
    }

    field_length= format_position[0] == 0 ? 4 : 2;
  }

  /*
    Only allow space in the first "part" of the datetime field and:
    - after days, part seconds
    - before and after AM/PM (handled by code later)

    2003-03-03 20:00:20 AM
    20:00:20.000000 AM 03-03-2000
  */
  i= max((uint) format_position[0], (uint) format_position[1]);
  set_if_bigger(i, (uint) format_position[2]);
  allow_space= ((1 << i) | (1 << format_position[6]));
  allow_space&= (1 | 2 | 4 | 8);

  not_zero_date= 0;
  for (i = start_loop;
       i < MAX_DATE_PARTS-1 && str != end &&
         my_isdigit(&my_charset_latin1,*str);
       i++)
  {
    const char *start= str;
    ulong tmp_value= (uint) (uchar) (*str++ - '0');

    /*
      Internal format means no delimiters; every field has a fixed
      width. Otherwise, we scan until we find a delimiter and discard
      leading zeroes -- except for the microsecond part, where leading
      zeroes are significant, and where we never process more than six
      digits.
    */
    my_bool     scan_until_delim= !is_internal_format &&
                                  ((i != format_position[6]));

    while (str != end && my_isdigit(&my_charset_latin1,str[0]) &&
           (scan_until_delim || --field_length))
    {
      tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0');
      str++;
    }
    date_len[i]= (uint) (str - start);
    if (tmp_value > 999999)                     /* Impossible date part */
    {
      *was_cut= 1;
      DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
    }
    date[i]=tmp_value;
    not_zero_date|= tmp_value;

    /* Length of next field */
    field_length= format_position[i+1] == 0 ? 4 : 2;

    if ((last_field_pos= str) == end)
    {
      i++;                                      /* Register last found part */
      break;
    }
    /* Allow a 'T' after day to allow CCYYMMDDT type of fields */
    if (i == format_position[2] && *str == 'T')
    {
      str++;                                    /* ISO8601:  CCYYMMDDThhmmss */
      continue;
    }
    if (i == format_position[5])                /* Seconds */
    {
      if (*str == '.')                          /* Followed by part seconds */
      {
        str++;
        field_length= 6;                        /* 6 digits */
      }
      continue;
    }
    while (str != end &&
           (my_ispunct(&my_charset_latin1,*str) ||
            my_isspace(&my_charset_latin1,*str)))
    {
      if (my_isspace(&my_charset_latin1,*str))
      {
        if (!(allow_space & (1 << i)))
        {
          *was_cut= 1;
          DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
        }
        found_space= 1;
      }
      str++;
      found_delimitier= 1;                      /* Should be a 'normal' date */
    }
    /* Check if next position is AM/PM */
    if (i == format_position[6])                /* Seconds, time for AM/PM */
    {
      i++;                                      /* Skip AM/PM part */
      if (format_position[7] != 255)            /* If using AM/PM */
      {
        if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
        {
          if (str[0] == 'p' || str[0] == 'P')
            add_hours= 12;
          else if (str[0] != 'a' || str[0] != 'A')
            continue;                           /* Not AM/PM */
          str+= 2;                              /* Skip AM/PM */
          /* Skip space after AM/PM */
          while (str != end && my_isspace(&my_charset_latin1,*str))
            str++;
        }
      }
    }
    last_field_pos= str;
  }
  if (found_delimitier && !found_space && (flags & TIME_DATETIME_ONLY))
  {
    *was_cut= 1;
    DBUG_RETURN(MYSQL_TIMESTAMP_NONE);          /* Can't be a datetime */
  }

  str= last_field_pos;

  number_of_fields= i - start_loop;
  while (i < MAX_DATE_PARTS)
  {
    date_len[i]= 0;
    date[i++]= 0;
  }

  if (!is_internal_format)
  {
    year_length= date_len[(uint) format_position[0]];
    if (!year_length)                           /* Year must be specified */
    {
      *was_cut= 1;
      DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
    }

    l_time->year=               date[(uint) format_position[0]];
    l_time->month=              date[(uint) format_position[1]];
    l_time->day=                date[(uint) format_position[2]];
    l_time->hour=               date[(uint) format_position[3]];
    l_time->minute=             date[(uint) format_position[4]];
    l_time->second=             date[(uint) format_position[5]];

    frac_pos= (uint) format_position[6];
    frac_len= date_len[frac_pos];
    if (frac_len < 6)
      date[frac_pos]*= (uint) log_10_int[6 - frac_len];
    l_time->second_part= date[frac_pos];

    if (format_position[7] != (uchar) 255)
    {
      if (l_time->hour > 12)
      {
        *was_cut= 1;
        goto err;
      }
      l_time->hour= l_time->hour%12 + add_hours;
    }
  }
  else
  {
    l_time->year=       date[0];
    l_time->month=      date[1];
    l_time->day=        date[2];
    l_time->hour=       date[3];
    l_time->minute=     date[4];
    l_time->second=     date[5];
    if (date_len[6] < 6)
      date[6]*= (uint) log_10_int[6 - date_len[6]];
    l_time->second_part=date[6];
  }
  l_time->neg= 0;

  if (year_length == 2 && not_zero_date)
    l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);

  if (number_of_fields < 3 ||
      l_time->year > 9999 || l_time->month > 12 ||
      l_time->day > 31 || l_time->hour > 23 ||
      l_time->minute > 59 || l_time->second > 59)
  {
    /* Only give warning for a zero date if there is some garbage after */
    if (!not_zero_date)                         /* If zero date */
    {
      for (; str != end ; str++)
      {
        if (!my_isspace(&my_charset_latin1, *str))
        {
          not_zero_date= 1;                     /* Give warning */
          break;
        }
      }
    }
    *was_cut= test(not_zero_date);
    goto err;
  }

  if (check_date(l_time, not_zero_date != 0, flags, was_cut))
    goto err;

  l_time->time_type= (number_of_fields <= 3 ?
                      MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);

  for (; str != end ; str++)
  {
    if (!my_isspace(&my_charset_latin1,*str))
    {
      *was_cut= 1;
      break;
    }
  }

  DBUG_RETURN(l_time->time_type);

err:
  bzero((char*) l_time, sizeof(*l_time));
  DBUG_RETURN(MYSQL_TIMESTAMP_ERROR);
}
Ejemplo n.º 20
0
/********************************************************************** 
  This one is more complicated; note that it may read in multiple lines.
***********************************************************************/
static const char *get_token_value(struct inputfile *inf)
{
  struct astring *partial;
  char *c, *start;
  char trailing;
  bool has_i18n_marking = FALSE;
  char border_character = '\"';
  
  assert(have_line(inf));

  c = inf->cur_line.str + inf->cur_line_pos;
  while(*c != '\0' && my_isspace(*c)) {
    c++;
  }
  if (*c == '\0')
    return NULL;

  if (*c == '-' || my_isdigit(*c)) {
    /* a number: */
    start = c++;
    while(*c != '\0' && my_isdigit(*c)) {
      c++;
    }
    /* check that the trailing stuff is ok: */
    if (!(*c == '\0' || *c == ',' || my_isspace(*c) || is_comment(*c))) {
      return NULL;
    }
    /* If its a comma, we don't want to obliterate it permanently,
     * so rememeber it: */
    trailing = *c;
    *c = '\0';
    
    inf->cur_line_pos = c - inf->cur_line.str;
    astr_minsize(&inf->token, strlen(start)+1);
    strcpy(inf->token.str, start);
    
    *c = trailing;
    return inf->token.str;
  }

  /* allow gettext marker: */
  if (*c == '_' && *(c+1) == '(') {
    has_i18n_marking = TRUE;
    c += 2;
    while(*c != '\0' && my_isspace(*c)) {
      c++;
    }
    if (*c == '\0')
      return NULL;
  }

  border_character = *c;

  if (border_character != '\"'
      && border_character != '\''
      && border_character != '$') {
    return NULL;
  }

  /* From here, we know we have a string, we just have to find the
     trailing (un-escaped) double-quote.  We read in extra lines if
     necessary to find it.  If we _don't_ find the end-of-string
     (that is, we come to end-of-file), we return NULL, but we
     leave the file in at_eof, and don't try to back-up to the
     current point.  (That would be more difficult, and probably
     not necessary: at that point we probably have a malformed
     string/file.)

     As we read extra lines, the string value from previous
     lines is placed in partial.
  */

  /* prepare for possibly multi-line string: */
  inf->string_start_line = inf->line_num;
  inf->in_string = TRUE;

  partial = &inf->partial;	/* abbreviation */
  astr_minsize(partial, 1);
  partial->str[0] = '\0';
  
  start = c++;			/* start includes the initial \", to
				   distinguish from a number */
  for(;;) {
    int pos;
    
    while(*c != '\0' && *c != border_character) {
      /* skip over escaped chars, including backslash-doublequote,
	 and backslash-backslash: */
      if (*c == '\\' && *(c+1) != '\0') {  
	c++;
      }
      c++;
    }

    if (*c == border_character) {
      /* Found end of string */
      break;
    }

    /* Accumulate to partial string and try more lines;
     * note partial->n must be _exactly_ the right size, so we
     * can strcpy instead of strcat-ing all the way to the end
     * each time. */
    pos = partial->n - 1;
    astr_minsize(partial, partial->n + c - start + 1);
    strcpy(partial->str + pos, start);
    strcpy(partial->str + partial->n - 2, "\n");
    
    if (!read_a_line(inf)) {
      /* shouldn't happen */
      inf_log(inf, LOG_ERROR, 
              "Bad return for multi-line string from read_a_line");
      return NULL;
    }
    c = start = inf->cur_line.str;
  }

  /* found end of string */
  *c = '\0';
  inf->cur_line_pos = c + 1 - inf->cur_line.str;
  astr_minsize(&inf->token, partial->n + strlen(start));
  strcpy(inf->token.str, partial->str);
  strcpy(inf->token.str + partial->n - 1, start);

  /* check gettext tag at end: */
  if (has_i18n_marking) {
    if (*++c == ')') {
      inf->cur_line_pos++;
    } else {
      inf_warn(inf, "Missing end of i18n string marking");
    }
  }
  inf->in_string = FALSE;
  return inf->token.str;
}
Ejemplo n.º 21
0
double my_strtod(const char *str, char **end_ptr, int *error)
{
  double result= 0.0;
  uint negative= 0, ndigits, dec_digits= 0, neg_exp= 0;
  int exponent= 0, digits_after_dec_point= 0, tmp_exp, step;
  const char *old_str, *end= *end_ptr, *start_of_number;
  char next_char;
  my_bool overflow=0;
  double scaler= 1.0;

  *error= 0;
  if (str >= end)
    goto done;

  while (my_isspace(&my_charset_latin1, *str))
  {
    if (++str == end)
      goto done;
  }

  start_of_number= str;
  if ((negative= (*str == '-')) || *str=='+')
  {
    if (++str == end)
      goto done;                                /* Could be changed to error */
  }

  /* Skip pre-zero for easier calculation of overflows */
  while (*str == '0')
  {
    if (++str == end)
      goto done;
    start_of_number= 0;                         /* Found digit */
  }

  old_str= str;
  while ((next_char= *str) >= '0' && next_char <= '9')
  {
    result= result*10.0 + (next_char - '0');
    scaler= scaler*10.0;
    if (++str == end)
    {
      next_char= 0;                             /* Found end of string */
      break;
    }
    start_of_number= 0;                         /* Found digit */
  }
  ndigits= (uint) (str-old_str);

  if (next_char == '.' && str < end-1)
  {
    /*
      Continue to add numbers after decimal point to the result, as if there
      was no decimal point. We will later (in the exponent handling) shift
      the number down with the required number of fractions.  We do it this
      way to be able to get maximum precision for numbers like 123.45E+02,
      which are normal for some ODBC applications.
    */
    old_str= ++str;
    while (my_isdigit(&my_charset_latin1, (next_char= *str)))
    {
      result= result*10.0 + (next_char - '0');
      digits_after_dec_point++;
      scaler= scaler*10.0;
      if (++str == end)
      {
        next_char= 0;
        break;
      }
    }
    /* If we found just '+.' or '.' then point at first character */
    if (!(dec_digits= (uint) (str-old_str)) && start_of_number)
      str= start_of_number;                     /* Point at '+' or '.' */
  }
  if ((next_char == 'e' || next_char == 'E') &&
      dec_digits + ndigits != 0 && str < end-1)
  {
    const char *old_str2= str++;

    if ((neg_exp= (*str == '-')) || *str == '+')
      str++;

    if (str == end || !my_isdigit(&my_charset_latin1, *str))
      str= old_str2;
    else
    {
      do
      {
        if (exponent < 9999)                    /* prot. against exp overfl. */
          exponent= exponent*10 + (*str - '0');
        str++;
      } while (str < end && my_isdigit(&my_charset_latin1, *str));
    }
  }
  tmp_exp= (neg_exp ? exponent + digits_after_dec_point :
            exponent - digits_after_dec_point);
  if (tmp_exp)
  {
    int order;
    /*
      Check for underflow/overflow.
      order is such an integer number that f = C * 10 ^ order,
      where f is the resulting floating point number and 1 <= C < 10.
      Here we compute the modulus
    */
    order= exponent + (neg_exp ? -1 : 1) * (ndigits - 1);
    if (order < 0)
      order= -order;
    if (order >= MAX_DBL_EXP && !neg_exp && result)
    {
      double c;
      /* Compute modulus of C (see comment above) */
      c= result / scaler * 10.0;
      if (order > MAX_DBL_EXP || c > MAX_RESULT_FOR_MAX_EXP)
      {
        overflow= 1;
        goto done;
      }
    }

    exponent= tmp_exp;
    if (exponent < 0)
    {
      exponent= -exponent;
      neg_exp= 1;                               /* neg_exp was 0 before */
    }
    step= array_elements(log_10) - 1;
    for (; exponent > step; exponent-= step)
      result= neg_exp ? result / log_10[step] : result * log_10[step];
    result= neg_exp ? result / log_10[exponent] : result * log_10[exponent];
  }

done:
  *end_ptr= (char*) str;                        /* end of number */

  if (overflow || my_isinf(result))
  {
    result= DBL_MAX;
    *error= EOVERFLOW;
  }

  return negative ? -result : result;
}
Ejemplo n.º 22
0
function (const char *nptr,char **endptr,int base)
{
  int negative;
  register ulongtype cutoff;
  register unsigned int cutlim;
  register ulongtype i;
  register const char *s;
  register uchar c;
  const char *save;
  int overflow;

  if (base < 0 || base == 1 || base > 36)
    base = 10;

  s = nptr;

  /* Skip white space.	*/
  while (my_isspace(&my_charset_latin1, *s))
    ++s;
  if (*s == '\0')
  {
    goto noconv;
  }

  /* Check for a sign.	*/
  negative= 0;
  if (*s == '-')
  {
    negative = 1;
    ++s;
  }
  else if (*s == '+')
  {
    ++s;
  }
    

  if (base == 16 && s[0] == '0' && my_toupper (&my_charset_latin1, s[1]) == 'X')
    s += 2;

  /* If BASE is zero, figure it out ourselves.	*/
  if (base == 0)
  {
    if (*s == '0')
    {
      if (my_toupper (&my_charset_latin1, s[1]) == 'X')
      {
	s += 2;
	base = 16;
      }
      else
	base = 8;
    }
    else
      base = 10;
  }

  /* Save the pointer so we can check later if anything happened.  */
  save = s;

  cutoff = UTYPE_MAX / (unsigned long int) base;
  cutlim = (uint) (UTYPE_MAX % (unsigned long int) base);

  overflow = 0;
  i = 0;
  for (c = *s; c != '\0'; c = *++s)
  {
    if (my_isdigit (&my_charset_latin1, c))
      c -= '0';
    else if (my_isalpha (&my_charset_latin1, c))
      c = my_toupper (&my_charset_latin1, c) - 'A' + 10;
    else
      break;
    if (c >= base)
      break;
    /* Check for overflow.  */
    if (i > cutoff || (i == cutoff && c > cutlim))
      overflow = 1;
    else
    {
      i *= (ulongtype) base;
      i += c;
    }
  }

  /* Check if anything actually happened.  */
  if (s == save)
    goto noconv;

  /* Store in ENDPTR the address of one character
     past the last character we converted.  */
  if (endptr != NULL)
    *endptr = (char *) s;

#ifndef USE_UNSIGNED
  /* Check for a value that is within the range of
     `unsigned long int', but outside the range of `long int'.	*/
  if (negative)
  {
    if (i  > (ulongtype) TYPE_MIN)
      overflow = 1;
  }
  else if (i > (ulongtype) TYPE_MAX)
    overflow = 1;
#endif

  if (overflow)
  {
    my_errno=ERANGE;
#ifdef USE_UNSIGNED
    return UTYPE_MAX;
#else
    return negative ? TYPE_MIN : TYPE_MAX;
#endif
  }

  /* Return the result of the appropriate sign.  */
  return (negative ? -((longtype) i) : (longtype) i);

noconv:
  /* There was no number to convert.  */
  my_errno=EDOM;
  if (endptr != NULL)
    *endptr = (char *) nptr;
  return 0L;
}
Ejemplo n.º 23
0
my_bool
str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
                ulonglong flags, MYSQL_TIME_STATUS *status)
{
  const char *end=str+length, *pos;
  uint number_of_fields= 0, digits, year_length, not_zero_date;
  DBUG_ENTER("str_to_datetime");
  bzero(l_time, sizeof(*l_time));

  if (flags & TIME_TIME_ONLY)
  {
    my_bool ret= str_to_time(str, length, l_time, flags, status);
    DBUG_RETURN(ret);
  }

  my_time_status_init(status);

  /* Skip space at start */
  for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++)
    ;
  if (str == end || ! my_isdigit(&my_charset_latin1, *str))
  {
    status->warnings= MYSQL_TIME_WARN_TRUNCATED;
    l_time->time_type= MYSQL_TIMESTAMP_NONE;
    DBUG_RETURN(1);
  }

  /*
    Calculate number of digits in first part.
    If length= 8 or >= 14 then year is of format YYYY.
    (YYYY-MM-DD,  YYYYMMDD, YYYYYMMDDHHMMSS)
  */
  pos= str;
  digits= skip_digits(&pos, end);

  if (pos < end && *pos == 'T') /* YYYYYMMDDHHMMSSThhmmss is supported too */
  {
    pos++;
    digits+= skip_digits(&pos, end);
  }
  if (pos < end && *pos == '.' && digits >= 12) /* YYYYYMMDDHHMMSShhmmss.uuuuuu is supported too */
  {
    pos++;
    skip_digits(&pos, end); // ignore the return value
  }

  if (pos == end)
  {
    /*
      Found date in internal format
      (only numbers like [YY]YYMMDD[T][hhmmss[.uuuuuu]])
    */
    year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
    if (get_digits(&l_time->year, &number_of_fields, &str, end, year_length) 
        || get_digits(&l_time->month, &number_of_fields, &str, end, 2)
        || get_digits(&l_time->day, &number_of_fields, &str, end, 2)
        || get_maybe_T(&str, end)
        || get_digits(&l_time->hour, &number_of_fields, &str, end, 2)
        || get_digits(&l_time->minute, &number_of_fields, &str, end, 2)
        || get_digits(&l_time->second, &number_of_fields, &str, end, 2))
     status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
  }
  else
  {
    const char *start= str;
    if (get_number(&l_time->year, &number_of_fields, &str, end))
      status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    year_length= str - start;

    if (!status->warnings &&
        (get_punct(&str, end)
         || get_number(&l_time->month, &number_of_fields, &str, end)
         || get_punct(&str, end)
         || get_number(&l_time->day, &number_of_fields, &str, end)
         || get_date_time_separator(&number_of_fields, flags, &str, end)
         || get_number(&l_time->hour, &number_of_fields, &str, end)
         || get_punct(&str, end)
         || get_number(&l_time->minute, &number_of_fields, &str, end)
         || get_punct(&str, end)
         || get_number(&l_time->second, &number_of_fields, &str, end)))
      status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
  }

  /* we're ok if date part is correct. even if the rest is truncated */
  if (number_of_fields < 3)
  {
    l_time->time_type= MYSQL_TIMESTAMP_NONE;
    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    DBUG_RETURN(TRUE);
  }

  if (!status->warnings && str < end && *str == '.')
  {
    str++;
    get_microseconds(&l_time->second_part, status,
                     &number_of_fields, &str, end);
  }

  not_zero_date = l_time->year || l_time->month || l_time->day ||
                  l_time->hour || l_time->minute || l_time->second ||
                  l_time->second_part;

  if (year_length == 2 && not_zero_date)
    l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);

  if (l_time->year > 9999 || l_time->month > 12 || l_time->day > 31 ||
      l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59)
  {
    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    goto err;
  }

  if (check_date(l_time, not_zero_date, flags, &status->warnings))
    goto err;

  l_time->time_type= (number_of_fields <= 3 ?
                      MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);

  for (; str != end ; str++)
  {
    if (!my_isspace(&my_charset_latin1,*str))
    {
      status->warnings= MYSQL_TIME_WARN_TRUNCATED;
      break;
    }
  }

  DBUG_RETURN(FALSE);

err:
  bzero((char*) l_time, sizeof(*l_time));
  l_time->time_type= MYSQL_TIMESTAMP_ERROR;
  DBUG_RETURN(TRUE);
}
Ejemplo n.º 24
0
my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
                    ulonglong fuzzydate, MYSQL_TIME_STATUS *status)
{
  ulong date[5];
  ulonglong value;
  const char *end=str+length, *end_of_days;
  my_bool found_days,found_hours, neg= 0;
  uint UNINIT_VAR(state);

  my_time_status_init(status);
  for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++)
    length--;
  if (str != end && *str == '-')
  {
    neg=1;
    str++;
    length--;
  }
  if (str == end)
  {
    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    goto err;
  }

  /* Check first if this is a full TIMESTAMP */
  if (length >= 12)
  {                                             /* Probably full timestamp */
    (void) str_to_datetime(str, length, l_time,
                           (fuzzydate & ~TIME_TIME_ONLY) | TIME_DATETIME_ONLY,
                            status);
    if (l_time->time_type >= MYSQL_TIMESTAMP_ERROR)
      return l_time->time_type == MYSQL_TIMESTAMP_ERROR;
    my_time_status_init(status);
  }

  l_time->neg= neg;
  /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
  for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
    value=value*10L + (long) (*str - '0');

  /* Skip all space after 'days' */
  end_of_days= str;
  for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++)
    ;

  found_days=found_hours=0;
  if ((uint) (end-str) > 1 && str != end_of_days &&
      my_isdigit(&my_charset_latin1, *str))
  {                                             /* Found days part */
    date[0]= (ulong) value;
    state= 1;                                   /* Assume next is hours */
    found_days= 1;
  }
  else if ((end-str) > 1 &&  *str == time_separator &&
           my_isdigit(&my_charset_latin1, str[1]))
  {
    date[0]= 0;                                 /* Assume we found hours */
    date[1]= (ulong) value;
    state=2;
    found_hours=1;
    str++;                                      /* skip ':' */
  }
  else
  {
    /* String given as one number; assume HHMMSS format */
    date[0]= 0;
    date[1]= (ulong) (value/10000);
    date[2]= (ulong) (value/100 % 100);
    date[3]= (ulong) (value % 100);
    state=4;
    goto fractional;
  }

  /* Read hours, minutes and seconds */
  for (;;)
  {
    for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
      value=value*10L + (long) (*str - '0');
    date[state++]= (ulong) value;
    if (state == 4 || (end-str) < 2 || *str != time_separator ||
        !my_isdigit(&my_charset_latin1,str[1]))
      break;
    str++;                                      /* Skip time_separator (':') */
  }

  if (state != 4)
  {                                             /* Not HH:MM:SS */
    /* Fix the date to assume that seconds was given */
    if (!found_hours && !found_days)
    {
      bmove_upp((uchar*) (date+4), (uchar*) (date+state),
                sizeof(long)*(state-1));
      bzero((uchar*) date, sizeof(long)*(4-state));
    }
    else
      bzero((uchar*) (date+state), sizeof(long)*(4-state));
  }

fractional:
  /* Get fractional second part */
  if (!status->warnings && str < end && *str == '.')
  {
    uint number_of_fields= 0;
    str++;
    get_microseconds(&date[4], status, &number_of_fields, &str, end);
  }
  else
    date[4]= 0;

  /* Check for exponent part: E<gigit> | E<sign><digit> */
  /* (may occur as result of %g formatting of time value) */
  if ((end - str) > 1 &&
      (*str == 'e' || *str == 'E') &&
      (my_isdigit(&my_charset_latin1, str[1]) ||
       ((str[1] == '-' || str[1] == '+') &&
        (end - str) > 2 &&
        my_isdigit(&my_charset_latin1, str[2]))))
  {
    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
    goto err;
  }

  if (internal_format_positions[7] != 255)
  {
    /* Read a possible AM/PM */
    while (str != end && my_isspace(&my_charset_latin1, *str))
      str++;
    if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
    {
      if (str[0] == 'p' || str[0] == 'P')
      {
        str+= 2;
        date[1]= date[1]%12 + 12;
      }
      else if (str[0] == 'a' || str[0] == 'A')
        str+=2;
    }
  }

  /* Integer overflow checks */
  if (date[0] > UINT_MAX || date[1] > UINT_MAX ||
      date[2] > UINT_MAX || date[3] > UINT_MAX ||
      date[4] > UINT_MAX)
  {
    status->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
    goto err;
  }  

  l_time->year=         0;                      /* For protocol::store_time */
  l_time->month=        0;
  l_time->day=          0;
  l_time->hour=         date[1] + date[0] * 24; /* Mix days and hours */
  l_time->minute=       date[2];
  l_time->second=       date[3];
  l_time->second_part=  date[4];
  l_time->time_type= MYSQL_TIMESTAMP_TIME;

  /* Check if the value is valid and fits into MYSQL_TIME range */
  if (check_time_range(l_time, 6, &status->warnings))
    return TRUE;

  /* Check if there is garbage at end of the MYSQL_TIME specification */
  if (str != end)
  {
    do
    {
      if (!my_isspace(&my_charset_latin1,*str))
      {
        status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
        break;
      }
    } while (++str != end);
  }
  return FALSE;

err:
  bzero((char*) l_time, sizeof(*l_time));
  l_time->time_type= MYSQL_TIMESTAMP_ERROR;
  return TRUE;
}