/* Reading the pattern itself */
static int
lex_pattern(usenet_parser_t self, int ch)
{
    /* Watch for EOF or linefeed */
    if (ch == EOF || ch == '\n') {
        /* Null-terminate the token */
        if (append_char(self, '\0') < 0) {
            return -1;
        }

        /* Do something interesting with the expression */
        if (accept_expression(self, self->field, self->operator,
                              self->token) < 0) {
            return -1;
        }

        /* This is also the end of the group entry */
        if (accept_group(self, self->has_not, self->group) < 0) {
            return -1;
        }

        free(self->group);

        /* Let the start state deal with the EOF or linefeed */
        return lex_start(self, ch);
    }

    /* Watch for the escape character */
    if (ch == '\\') {
        self->state = lex_pattern_esc;
        return 0;
    }

    /* Watch for other whitespace */
    if (isspace(ch)) {
        /* Record the position of the whitespace for later trimming */
        self->token_mark = self->token_pointer;
        self->state = lex_pattern_ws;
        return append_char(self, ch);
    }

    /* Watch for a separator */
    if (ch == '/') {
        /* Null-terminate the token */
        if (append_char(self, '\0') < 0) {
            return -1;
        }

        /* Do something interesting with the expression */
        self->token_pointer = self->token;
        self->state = lex_field_start;
        return accept_expression(self, self->field, self->operator,
                                 self->token);
    }

    /* Anything else is part of the pattern */
    return append_char(self, ch);
}
/* We've got some whitespace in the group pattern.  It could mean that
 * the "not" keyword was used or it could mean that we've just got
 * some space between the pattern and the separator character */
static int
lex_group_ws(usenet_parser_t self, int ch)
{
    /* Watch for EOF or newline */
    if (ch == EOF || ch == '\n') {
        /* This is a nice, short group entry */
        if (accept_group(self, self->has_not, self->token) < 0) {
            return -1;
        }

        return lex_start(self, ch);
    }

    /* Skip additional whitespace */
    if (isspace(ch)) {
        return 0;
    }

    /* Watch for an escape character */
    if (ch == '\\') {
        self->state = lex_group_esc;
        return 0;
    }

    /* Watch for the separator character */
    if (ch == '/') {
        /* Record the group name for later */
        self->group = strdup(self->token);
        self->token_pointer = self->token;
        self->state = lex_field_start;
        return 0;
    }

    /* Anything else wants to be part of the pattern.  Make sure that
     * the token we've already read is "not" and that we're not doing
     * the double-negative thing */
    if (strcmp(self->token, T_NOT) != 0) {
        parse_error(self, "expected '/' or newline");
        return -1;
    }

    /* Watch for double-negative */
    if (self->has_not) {
        parse_error(self, "double negative not permitted");
        return -1;
    }

    /* This is a negated group pattern */
    self->has_not = 1;
    self->token_pointer = self->token;

    /* Anything else is part of the group pattern */
    self->state = lex_group;
    return append_char(self, ch);
}
/* Reading trailing whitespace after a pattern */
static int
lex_pattern_ws(usenet_parser_t self, int ch)
{
    /* Watch for EOF and newline */
    if (ch == EOF || ch == '\n') {
        /* Trim off the trailing whitespace */
        *self->token_mark = '\0';

        /* Do something interesting with the expression */
        if (accept_expression(self, self->field, self->operator,
                              self->token) < 0) {
            return -1;
        }

        /* This is also the end of the group entry */
        if (accept_group(self, self->has_not, self->group) < 0) {
            return -1;
        }

        free(self->group);

        /* Let the start state deal with the EOF or newline */
        return lex_start(self, ch);
    }

    /* Skip any other whitespace */
    if (isspace(ch)) {
        return append_char(self, ch);
    }

    /* Watch for an escape character */
    if (ch == '\\') {
        self->state = lex_pattern_esc;
        return 0;
    }

    /* Watch for a separator */
    if (ch == '/') {
        /* Trim off the trailing whitespace */
        *self->token_mark = '\0';

        /* Do something interesting with the expression */
        self->token_pointer = self->token;
        self->state = lex_field_start;
        return accept_expression(self, self->field, self->operator,
                                 self->token);
    }

    /* Anything else is more of the pattern */
    self->state = lex_pattern;
    return append_char(self, ch);
}
/* Reading the group (or its preceding `not') */
static int
lex_group(usenet_parser_t self, int ch)
{
    /* Watch for EOF or newline */
    if (ch == EOF || ch == '\n') {
        /* Null-terminate the token */
        if (append_char(self, '\0') < 0) {
            return -1;
        }

        /* This is a nice, short group entry */
        if (accept_group(self, self->has_not, self->token) < 0) {
            return -1;
        }

        return lex_start(self, ch);
    }

    /* Watch for other whitespace */
    if (isspace(ch)) {
        self->state = lex_group_ws;

        /* Null-terminate the token */
        return append_char(self, '\0');
    }

    /* Watch for an escape character */
    if (ch == '\\') {
        self->state = lex_group_esc;
        return 0;
    }

    /* Watch for the separator character */
    if (ch == '/') {
        /* Null-terminate the token */
        if (append_char(self, '\0') < 0) {
            return -1;
        }

        /* Record the group name for later use */
        self->group = strdup(self->token);
        self->token_pointer = self->token;
        self->state = lex_field_start;
        return 0;
    }

    /* Anything else is part of the group pattern */
    return append_char(self, ch);
}
bool servers_init(bool dont_read_servers_table)
{
  THD  *thd;
  bool return_val= FALSE;
  DBUG_ENTER("servers_init");

  /* init the mutex */
  if (my_rwlock_init(&THR_LOCK_servers, NULL))
    DBUG_RETURN(TRUE);

  /* initialise our servers cache */
  if (hash_init(&servers_cache, system_charset_info, 32, 0, 0,
                (hash_get_key) servers_cache_get_key, 0, 0))
  {
    return_val= TRUE; /* we failed, out of memory? */
    goto end;
  }

  /* Initialize the mem root for data */
  init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0);

  if (dont_read_servers_table)
    goto end;

  /*
    To be able to run this from boot, we allocate a temporary THD
  */
  if (!(thd=new THD))
    DBUG_RETURN(TRUE);
  thd->thread_stack= (char*) &thd;
  thd->store_globals();
  lex_start(thd);
  /*
    It is safe to call servers_reload() since servers_* arrays and hashes which
    will be freed there are global static objects and thus are initialized
    by zeros at startup.
  */
  return_val= servers_reload(thd);
  delete thd;
  /* Remember that we don't have a THD */
  my_pthread_setspecific_ptr(THR_THD,  0);

end:
  DBUG_RETURN(return_val);
}
/* Reading a comment (to end-of-line) */
static int
lex_comment(usenet_parser_t self, int ch)
{
    /* Watch for end-of-file */
    if (ch == EOF) {
        return lex_start(self, ch);
    }

    /* Watch for end of line */
    if (ch == '\n') {
        self->state = lex_start;
        self->line_num++;
        return 0;
    }

    /* Ignore everything else */
    return 0;
}