示例#1
0
   variants arrayFromStream( T& in )
   {
      variants ar;
      try
      {
        if( in.peek() != '[' )
           FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" );
        in.get();
        skip_white_space(in);

        while( in.peek() != ']' )
        {
           if( in.peek() == ',' )
           {
              in.get();
              continue;
           }
           if( skip_white_space(in) ) continue;
           ar.push_back( variant_from_stream<T, parser_type>(in) );
           skip_white_space(in);
        }
        if( in.peek() != ']' )
           FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}",
                                    ("variant", ar) );

        in.get();
      } FC_RETHROW_EXCEPTIONS( warn, "Attempting to parse array ${array}",
                                         ("array", ar ) );
      return ar;
   }
示例#2
0
/**
	@brief Parse a JSON string into a jsonObject.
	@param s Pointer to the string to be parsed.
	@param decode A boolean; true means decode class hints, false means don't.
	@return Pointer to the newly created jsonObject.

	Set up a Parser.  Call get_json_node() to do the real work, then make sure that there's
	nothing but white space at the end.
*/
static jsonObject* parse_it( const char* s, int decode ) {

	if( !s || !*s )
		return NULL;    // Nothing to parse

	Parser parser;

	parser.str_buf = NULL;
	parser.index = 0;
	parser.buff = s;
	parser.decode = decode;

	jsonObject* obj = get_json_node( &parser, skip_white_space( &parser ) );

	// Make sure there's nothing but white space at the end
	char c;
	if( obj && (c = skip_white_space( &parser )) ) {
		report_error( &parser, c, "Extra material follows JSON string" );
		jsonObjectFree( obj );
		obj = NULL;
	}

	buffer_free( parser.str_buf );
	return obj;
}
示例#3
0
static int json_parse_object_tail(struct json_parser* parser)
{
    for (;;)
    {
        skip_white_space(parser);
    
        switch (peek(parser))
        {
            // Finished when we reach the final closing brace
            case '}':
                skip(parser);
                return JSON_PARSE_SUCCESS;
                
            case '"':
                
                // Key
                skip(parser);
                json_parse_string_tail(parser);
                
                // Sep
                skip_white_space(parser);
                skip_char(parser, ':');
                
                // Value
                json_parse_value(parser);
                
                
                // Comma?
                break;
                
            default:
                return JSON_PARSE_FAIL;
        }
    }    
}
示例#4
0
/**
	@brief Parse an array, and create a JSON_ARRAY for it.
	@param parser Pointer to a Parser.
	@return Pointer to a newly created jsonObject of type JSON_ARRAY, or NULL upon error.

	Look for a series of JSON nodes, separated by commas and terminated by a right square
	bracket.  Parse each node recursively, collect them all into a newly created jsonObject
	of type JSON_ARRAY, and return a pointer to the result.

	Upon error, log an error message and return NULL.
*/
static jsonObject* get_array( Parser* parser ) {

	jsonObject* array = jsonNewObjectType( JSON_ARRAY );

	char c = skip_white_space( parser );
	if( ']' == c )
		return array;          // Empty array

	for( ;; ) {
		jsonObject* obj = get_json_node( parser, c );
		if( !obj ) {
			jsonObjectFree( array );
			return NULL;         // Failed to get anything
		}

		// Add the entry to the array
		jsonObjectPush( array, obj );

		// Look for a comma or right bracket
		c = skip_white_space( parser );
		if( ']' == c )
			break;
		else if( c != ',' ) {
			report_error( parser, c, "Expected comma or bracket in array; didn't find it\n" );
			jsonObjectFree( array );
			return NULL;
		}
		c = skip_white_space( parser );
	}

	return array;
}
示例#5
0
static
#endif
bool
compare_argument(string_view_t a, string_view_t b)
{
	string_view_t str_a = pfq_signature_simplify(a);
	string_view_t str_b = pfq_signature_simplify(b);

	const char *ap = str_a.begin;
	const char *bp = str_b.begin;

	while (ap != str_a.end && bp != str_b.end)
	{
		if (*ap != *bp)
			return false;

		if (isspace(*ap)) {
			ap = skip_white_space(ap, str_a.end);
			bp = skip_white_space(bp, str_b.end);
		}
		else {
			ap++, bp++;
		}
	}

	return ap == str_a.end && bp == str_b.end;
}
/* Search for equate entry of the form "define token = value". */
unsigned long equate_seek_entry(const char *token, unsigned char *buffer, unsigned long offset, unsigned long max)
{
	unsigned long linemax, mark;

	while (offset < max)
	{
		/* Search line-by-line for ini section header, skip past comments marked with a semi-colon. */
		if ((mark = seek_token_lined("define", buffer, offset, max, ';', FALSE, TRUE)) < max)
		{
			linemax = seek_endline(buffer, ';', mark, max);
			if ((mark = seek_token(token, buffer, mark, linemax, FALSE, TRUE)) < linemax)
			{
				mark = skip_white_space(buffer, mark, linemax);
				if (buffer[mark] == '=')
				{
					mark = skip_white_space(buffer, mark + 1, linemax);
					return mark;
				}
			}
		}
		offset = mark;
	}

	return max;
}
示例#7
0
文件: json.cpp 项目: dbarobin/steem
   variant_object objectFromStream( T& in, uint32_t depth )
   {
      depth++;
      FC_ASSERT( depth <= JSON_MAX_RECURSION_DEPTH );
      mutable_variant_object obj;
      try
      {
         char c = in.peek();
         if( c != '{' )
            FC_THROW_EXCEPTION( parse_error_exception,
                                     "Expected '{', but read '${char}'",
                                     ("char",string(&c, &c + 1)) );
         in.get();
         skip_white_space( in, depth );
         while( in.peek() != '}' )
         {
            if( in.peek() == ',' )
            {
               in.get();
               continue;
            }
            if( skip_white_space( in, depth ) ) continue;
            string key = stringFromStream( in, depth );
            skip_white_space( in, depth );
            if( in.peek() != ':' )
            {
               FC_THROW_EXCEPTION( parse_error_exception, "Expected ':' after key \"${key}\"",
                                        ("key", key) );
            }
            in.get();
            auto val = variant_from_stream<T, parser_type>( in, depth );

            obj(std::move(key),std::move(val));
            skip_white_space( in, depth );
         }
         if( in.peek() == '}' )
         {
            in.get();
            return obj;
         }
         FC_THROW_EXCEPTION( parse_error_exception, "Expected '}' after ${variant}", ("variant", obj ) );
      }
      catch( const fc::eof_exception& e )
      {
         FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.to_detail_string() ) );
      }
      catch( const std::ios_base::failure& e )
      {
         FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.what() ) );
      } FC_RETHROW_EXCEPTIONS( warn, "Error parsing object" );
   }
示例#8
0
文件: xpp.c 项目: pmolfese/nidb
char *parse_id(char *p, char *buf)
{
  int i;
  char quote_ch;

  i = 0;
  skip_white_space(&p);
  // Get pp identifier.
  if (*p == '"' || *p == '\'') {
    // If first char is a quote then the id includes everything up to the closing quote.
    quote_ch = *p;
    ++p; // skip the opening quote
    while (*p && *p != quote_ch) {
      buf[i++] = *p++;
    }
    ++p; // point to char after closing quote
  }
  else {
    // If first char is not a quote then id includes everything up to the first
    // whitespace or newline char.
    while (!is_word_end(*p)) {
      buf[i++] = *p++;
    }
  }
  buf[i] = 0; // terminate string
  return p; // points to first char after id
}
示例#9
0
文件: ft_atoi.c 项目: YOKOKOYO/libft
int				ft_atoi(const char *str)
{
	long long	result;
	int			neg;
	size_t		size;
	char		*s;

	neg = 1;
	result = 0;
	s = skip_white_space(str);
	if (!s)
		return (0);
	if (*s == '+')
		s++;
	else if (*s == '-')
	{
		s++;
		neg = -1;
	}
	s = skip_nul(s);
	size = get_size(s);
	while (ft_isdigit((int)*s))
	{
		result += (*s - '0') * ft_pow(10, size-- - 1);
		s++;
	}
	return (result * neg);
}
示例#10
0
void
print_code(BPath& path, int32 code)
{
	FILE* file = fopen(path.Path(), "r");
	if (file == NULL)
		return;

	int32 lineNumber = 0;
	char buffer[4096];

	while (fgets(buffer, sizeof(buffer), file) != NULL) {
		char* line = buffer;
		skip_white_space(line);

		if (strncmp(line, "AS_", 3))
			continue;

		if (++lineNumber != code)
			continue;

		get_name(line);
		printf("code %ld: %s\n", lineNumber, line);
		fclose(file);
		return;
	}

	printf("unknown code %ld!\n", code);
	fclose(file);
}
示例#11
0
文件: common.c 项目: GisKook/Gis
/*
 * Check whether the specified command is a SELECT (or VALUES).
 */
static bool
is_select_command(const char *query)
{
	int			wordlen;

	/*
	 * First advance over any whitespace, comments and left parentheses.
	 */
	for (;;)
	{
		query = skip_white_space(query);
		if (query[0] == '(')
			query++;
		else
			break;
	}

	/*
	 * Check word length (since "selectx" is not "select").
	 */
	wordlen = 0;
	while (isalpha((unsigned char) query[wordlen]))
		wordlen += PQmblen(&query[wordlen], pset.encoding);

	if (wordlen == 6 && pg_strncasecmp(query, "select", 6) == 0)
		return true;

	if (wordlen == 6 && pg_strncasecmp(query, "values", 6) == 0)
		return true;

	return false;
}
示例#12
0
文件: json.cpp 项目: bitshares/fc
   variants arrayFromStreamBase( T& in, std::function<variant(T&)>& get_value  )
   {
      variants ar;
      try
      {
        if( in.peek() != '[' )
           FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" );
        in.get();

        while( in.peek() != ']' )
        {
           if( in.peek() == ',' )
           {
              in.get();
              continue;
           }
           if( skip_white_space(in) ) continue;
           ar.push_back( get_value(in) );
        }
        if( in.peek() != ']' )
           FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}",
                                    ("variant", ar) );

        in.get();
      } FC_RETHROW_EXCEPTIONS( warn, "Attempting to parse array ${array}",
                                         ("array", ar ) );
      return ar;
   }
char * get_number()
{
	if (!isdigit(g_current_char))
	{
		char unexpected_token[2];
		unexpected_token[0] = g_current_char;
		unexpected_token[1] = '\0';
		unexpected_token_received("0-9", unexpected_token);
	}
	else
	{
		char * rtn = (char *) calloc(MAX_NUMBER_SIZE, sizeof(char));
		int i = 0;
		while(isdigit(g_current_char)) {
			rtn[i++] = g_current_char;
			read_char();
			if (i == MAX_NUMBER_SIZE && isalnum(g_current_char)) {
				printf("Number %s was too large, must be no longer than %d digits", 
					rtn, MAX_NUMBER_SIZE - 1);
				abort_compile("Compilation aborted");
			}
		}
		skip_white_space();
		return rtn;
	}
}
示例#14
0
static int 
tokenize(mvc * c, int cur)
{
	struct scanner *lc = &c->scanner;
	while (1) {
		if (cur == 0xFEFF) {
			/* on Linux at least, iswpunct returns TRUE
			 * for U+FEFF, but we don't want that, we just
			 * want to go to the scanner_error case
			 * below */
			;
		} else if (iswspace(cur)) {
			if ((cur = skip_white_space(lc)) == EOF)
				return cur;
			continue;  /* try again */
		} else if (iswdigit(cur)) {
			return number(c, cur);
		} else if (iswalpha(cur) || cur == '_') {
			return keyword_or_ident(c, cur);
		} else if (iswpunct(cur)) {
			return scanner_symbol(c, cur);
		}
		if (cur == EOF) {
			if (lc->mode == LINE_1 || !lc->started )
				return cur;
			return scanner_error(c, cur);
		}
		/* none of the above: error */
		return scanner_error(c, cur);
	}
}
示例#15
0
bool option_db_t::parse_file( FILE* file )
{
  char buffer[ 1024 ];
  bool first = true;
  while ( fgets( buffer, sizeof( buffer ), file ) )
  {
    char *b = buffer;
    if ( first )
    {
      first = false;

      // Skip the UTF-8 BOM, if any.
      size_t len = strlen( b );
      if ( len >= 3 && utf8::is_bom( b ) )
        b += 3;
    }

    b = skip_white_space( b );
    if ( *b == '#' || *b == '\0' )
      continue;

    parse_line( io::maybe_latin1_to_utf8( b ) );
  }
  return true;
}
示例#16
0
文件: json.cpp 项目: bitshares/fc
   variant_object objectFromStreamBase( T& in, std::function<std::string(T&)>& get_key, std::function<variant(T&)>& get_value )
   {
      mutable_variant_object obj;
      try
      {
         char c = in.peek();
         if( c != '{' )
            FC_THROW_EXCEPTION( parse_error_exception,
                                     "Expected '{', but read '${char}'",
                                     ("char",string(&c, &c + 1)) );
         in.get();
         while( in.peek() != '}' )
         {
            if( in.peek() == ',' )
            {
               in.get();
               continue;
            }
            if( skip_white_space(in) ) continue;
            string key = get_key( in );
            skip_white_space(in);
            if( in.peek() != ':' )
            {
               FC_THROW_EXCEPTION( parse_error_exception, "Expected ':' after key \"${key}\"",
                                        ("key", key) );
            }
            in.get();
            auto val = get_value( in );

            obj(std::move(key),std::move(val));
         }
         if( in.peek() == '}' )
         {
            in.get();
            return obj;
         }
         FC_THROW_EXCEPTION( parse_error_exception, "Expected '}' after ${variant}", ("variant", obj ) );
      }
      catch( const fc::eof_exception& e )
      {
         FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.to_detail_string() ) );
      }
      catch( const std::ios_base::failure& e )
      {
         FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.what() ) );
      } FC_RETHROW_EXCEPTIONS( warn, "Error parsing object" );
   }
示例#17
0
static int
read_int( FILE *fp, int *i )
{
	skip_white_space( fp );
	if( fscanf( fp, "%d", i ) != 1 ) {
		im_error( "im_ppm2vips", "%s", _( "bad int" ) );
		return( -1 );
	}

	return( 0 );
}
示例#18
0
static int
read_float( FILE *fp, float *f )
{
	skip_white_space( fp );
	if( fscanf( fp, "%f", f ) != 1 ) {
		im_error( "im_ppm2vips", "%s", _( "bad float" ) );
		return( -1 );
	}

	return( 0 );
}
示例#19
0
static void skip_white_space( FILE * fp )
{
	int ch;
	while( isspace( ch = fgetc( fp ) ) )
		;
	ungetc( ch, fp );

	if( ch == '#' ) {
		skip_line( fp );
		skip_white_space( fp );
	}
}
示例#20
0
文件: json.cpp 项目: dbarobin/steem
   variant variant_from_stream( T& in, uint32_t depth )
   {
      depth++;
      FC_ASSERT( depth <= JSON_MAX_RECURSION_DEPTH );
      skip_white_space( in, depth );
      variant var;
      while( true )
      {
         signed char c = in.peek();
         switch( c )
         {
            case ' ':
            case '\t':
            case '\n':
            case '\r':
              in.get();
              continue;
            case '"':
              return stringFromStream( in, depth );
            case '{':
              return objectFromStream<T, parser_type>( in, depth );
            case '[':
              return arrayFromStream<T, parser_type>( in, depth );
            case '-':
            case '.':
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
              return number_from_stream<T, parser_type>( in, depth );
            // null, true, false, or 'warning' / string
            case 'n':
            case 't':
            case 'f':
              return token_from_stream( in, depth );
            case 0x04: // ^D end of transmission
            case EOF:
            case 0:
              FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
            default:
              FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
                                 ("c", c)("s", stringFromToken( in, depth )) );
         }
      }
	  return variant();
   }
示例#21
0
 variant variant_from_stream( T& in, uint32_t max_depth )
 {
    if( max_depth == 0 )
        FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" );
    skip_white_space(in);
    signed char c = in.peek();
    switch( c )
    {
       case '"':
          return json_relaxed::stringFromStream<T, strict>( in );
       case '{':
          return json_relaxed::objectFromStream<T, strict>( in, max_depth - 1 );
       case '[':
          return json_relaxed::arrayFromStream<T, strict>( in, max_depth - 1 );
       case '-':
       case '+':
       case '.':
       case '0':
       case '1':
       case '2':
       case '3':
       case '4':
       case '5':
       case '6':
       case '7':
       case '8':
       case '9':
          return json_relaxed::numberFromStream<T, strict>( in );
       // null, true, false, or 'warning' / string
       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
       case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
       case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
       case 'y': case 'z':
       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H':
       case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
       case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
       case 'Y': case 'Z':
       case '_':                               case '/':
          return json_relaxed::wordFromStream<T, strict>( in );
       case 0x04: // ^D end of transmission
       case EOF:
          FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
       case 0:
       default:
          FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
                              ("c", c)("s", stringFromToken(in)) );
    }
 }
示例#22
0
/** ignore tab space '\n comment */
void preprocess(){
    while(1){
        if(ch == ' ' || ch == '\t' || ch == '\r')
            skip_white_space();
        else if(ch == '/'){
                        ///向前多看一个字符来判断是否为注释,若不是在放回缓冲区中
            getch();
            if(ch=='*')
                parse_comment();
            else{
                ungetc(ch,fin);///rollback char
                ch = '/';
                break;
            }
        }else
            break;
    }
}
示例#23
0
文件: json.cpp 项目: bitshares/fc
  variant variant_from_stream( T& in, uint32_t max_depth )
  {
     if( max_depth == 0 )
         FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" );
     skip_white_space(in);
     signed char c = in.peek();
     switch( c )
     {
        case '"':
           return stringFromStream( in );
        case '{':
           return objectFromStream<T, parser_type>( in, max_depth - 1 );
        case '[':
           return arrayFromStream<T, parser_type>( in, max_depth - 1 );
        case '-':
        case '.':
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
           return number_from_stream<T, parser_type>( in );
        // null, true, false, or 'warning' / string
        case 'n':
        case 't':
        case 'f':
           return token_from_stream( in );
        case 0x04: // ^D end of transmission
        case EOF:
           FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
        case 0:
           if( parser_type == fc::json::broken_nul_parser )
              return variant();
           FALLTHROUGH
        default:
           FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
                               ("c", c)("s", stringFromToken(in)) );
     }
 }
void match_token(const char c)
{
	if (g_current_char == c)
	{
		read_char();
		skip_white_space();
	} 
	else
	{
		char expected_token[2];
		expected_token[0] = c;
		expected_token[1] = '\0';

		char unexpected_token[2];
		unexpected_token[0] = g_current_char;
		unexpected_token[1] = '\0';
		unexpected_token_received(expected_token, unexpected_token);
	}
}
/* Search for token in buffer using rule that token must exist on a single line with optional comments. */
unsigned long seek_token_lined(const char *token, unsigned char *buffer,
	unsigned long offset, unsigned long max, const char comment, bool case_sensitive, bool advance)
{
	unsigned long endline;

	while (offset < max)
	{
		/* Find the end of the line terminated by newline, carriage return, or start of comment. */
		offset = skip_white_space(buffer, offset, max);
		if ((endline = seek_endline(buffer, comment, offset, max)) < (max - 1))
			endline++;

		/* Seek token on single line. */
		if ((offset = seek_token(token, buffer, offset, endline, case_sensitive, advance)) < endline)
			break;

		/* Advance to true end of line including comments. */
		offset = seek_endline(buffer, '\0', offset, max);
	}

	return offset;
}
示例#26
0
static int json_parse_array_tail(struct json_parser* parser)
{
    for (;;)
    {
        if (peek(parser) == ']')
        {
            skip(parser);
            return JSON_PARSE_SUCCESS;
        }

        int more = 0;
        do
        {
            json_parse_value(parser);
            skip_white_space(parser);
            if (peek(parser) == ',')
            {
                skip(parser);
                more = 1;
            }
        } while (more);
    }
}
示例#27
0
文件: xpp.c 项目: pmolfese/nidb
void pp_define(char *p, bool ww)
{
  int i, si;

  p = parse_id(p, m_id_buf);
  si = get_symbol_index(m_id_buf);
  if (si < 0) {
    si = m_symbol_len; // not defined so add it
    strcpy(m_symbol[si].id, m_id_buf);
    m_symbol[si].val[0] = 0; // default val is empty str
    ++m_symbol_len;
  }                   // else if defined change its value

  if (!is_line_end(*p)) {
    skip_white_space(&p);
    i = 0;
    while (!is_line_end(*p)) { // get pp value, to end of line
      m_symbol[si].val[i++] = *p++;
    }
    m_symbol[si].val[i] = 0; // terminate string
  }
  m_symbol[si].ww = ww; // to use whole-word search or not
}
示例#28
0
static unsigned int read_uint( FILE *fp )
{
	int i;
	char buf[80];
	int ch;

	skip_white_space( fp );

	/* Stop complaints about used-before-set on ch.
	 */
	ch = -1;

	for( i = 0; i < 80 - 1 && isdigit( ch = fgetc( fp ) ); i++ )
		buf[i] = ch;
	buf[i] = '\0';

	if( i == 0 ) {
		return( -1 );
	}

	ungetc( ch, fp );

	return( atoi( buf ) );
}
示例#29
0
char *include_directive(FILE *file)
{
#define MAXBUF 256
    char tmp[MAXBUF];
    int n = 0;
    int i;

    skip_white_space(file);	/* Allow for #   include */
    
    if ((i = getc(file)) == EOF) return 0;

    if (i != 'i')		/* Not an include directive */
	return 0;

    while ((i = getc(file)) != EOF)  {/* Find first quote */
	if (i == '"')
	    break;
	if (i == '\n') return 0; /* Don't wrap lines in bad code */
    }

    if (i == EOF) return 0;

    while ((i = getc(file)) != EOF)  {/* Find first quote */
	if (i == '\n')
	    return 0;		/* Mangled code */
	else if (i == '"') 
	    break;
	if (n >= (MAXBUF-1)) {
	    fprintf(stderr,"dependencies: include file name too long\n");
	    exit(1);
	}
	tmp[n++] = i;
    }
    tmp[n] = 0;
    return strdup(tmp);
}
示例#30
0
文件: common.c 项目: GisKook/Gis
/*
 * Check whether a command is one of those for which we should NOT start
 * a new transaction block (ie, send a preceding BEGIN).
 *
 * These include the transaction control statements themselves, plus
 * certain statements that the backend disallows inside transaction blocks.
 */
static bool
command_no_begin(const char *query)
{
	int			wordlen;

	/*
	 * First we must advance over any whitespace and comments.
	 */
	query = skip_white_space(query);

	/*
	 * Check word length (since "beginx" is not "begin").
	 */
	wordlen = 0;
	while (isalpha((unsigned char) query[wordlen]))
		wordlen += PQmblen(&query[wordlen], pset.encoding);

	/*
	 * Transaction control commands.  These should include every keyword that
	 * gives rise to a TransactionStmt in the backend grammar, except for the
	 * savepoint-related commands.
	 *
	 * (We assume that START must be START TRANSACTION, since there is
	 * presently no other "START foo" command.)
	 */
	if (wordlen == 5 && pg_strncasecmp(query, "abort", 5) == 0)
		return true;
	if (wordlen == 5 && pg_strncasecmp(query, "begin", 5) == 0)
		return true;
	if (wordlen == 5 && pg_strncasecmp(query, "start", 5) == 0)
		return true;
	if (wordlen == 6 && pg_strncasecmp(query, "commit", 6) == 0)
		return true;
	if (wordlen == 3 && pg_strncasecmp(query, "end", 3) == 0)
		return true;
	if (wordlen == 8 && pg_strncasecmp(query, "rollback", 8) == 0)
		return true;
	if (wordlen == 7 && pg_strncasecmp(query, "prepare", 7) == 0)
	{
		/* PREPARE TRANSACTION is a TC command, PREPARE foo is not */
		query += wordlen;

		query = skip_white_space(query);

		wordlen = 0;
		while (isalpha((unsigned char) query[wordlen]))
			wordlen += PQmblen(&query[wordlen], pset.encoding);

		if (wordlen == 11 && pg_strncasecmp(query, "transaction", 11) == 0)
			return true;
		return false;
	}

	/*
	 * Commands not allowed within transactions.  The statements checked for
	 * here should be exactly those that call PreventTransactionChain() in the
	 * backend.
	 */
	if (wordlen == 6 && pg_strncasecmp(query, "vacuum", 6) == 0)
		return true;
	if (wordlen == 7 && pg_strncasecmp(query, "cluster", 7) == 0)
	{
		/* CLUSTER with any arguments is allowed in transactions */
		query += wordlen;

		query = skip_white_space(query);

		if (isalpha((unsigned char) query[0]))
			return false;		/* has additional words */
		return true;			/* it's CLUSTER without arguments */
	}

	if (wordlen == 6 && pg_strncasecmp(query, "create", 6) == 0)
	{
		query += wordlen;

		query = skip_white_space(query);

		wordlen = 0;
		while (isalpha((unsigned char) query[wordlen]))
			wordlen += PQmblen(&query[wordlen], pset.encoding);

		if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
			return true;
		if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
			return true;

		/* CREATE [UNIQUE] INDEX CONCURRENTLY isn't allowed in xacts */
		if (wordlen == 6 && pg_strncasecmp(query, "unique", 6) == 0)
		{
			query += wordlen;

			query = skip_white_space(query);

			wordlen = 0;
			while (isalpha((unsigned char) query[wordlen]))
				wordlen += PQmblen(&query[wordlen], pset.encoding);
		}

		if (wordlen == 5 && pg_strncasecmp(query, "index", 5) == 0)
		{
			query += wordlen;

			query = skip_white_space(query);

			wordlen = 0;
			while (isalpha((unsigned char) query[wordlen]))
				wordlen += PQmblen(&query[wordlen], pset.encoding);

			if (wordlen == 12 && pg_strncasecmp(query, "concurrently", 12) == 0)
				return true;
		}

		return false;
	}

	/*
	 * Note: these tests will match DROP SYSTEM and REINDEX TABLESPACE, which
	 * aren't really valid commands so we don't care much. The other four
	 * possible matches are correct.
	 */
	if ((wordlen == 4 && pg_strncasecmp(query, "drop", 4) == 0) ||
		(wordlen == 7 && pg_strncasecmp(query, "reindex", 7) == 0))
	{
		query += wordlen;

		query = skip_white_space(query);

		wordlen = 0;
		while (isalpha((unsigned char) query[wordlen]))
			wordlen += PQmblen(&query[wordlen], pset.encoding);

		if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
			return true;
		if (wordlen == 6 && pg_strncasecmp(query, "system", 6) == 0)
			return true;
		if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
			return true;
		return false;
	}

	/* DISCARD ALL isn't allowed in xacts, but other variants are allowed. */
	if (wordlen == 7 && pg_strncasecmp(query, "discard", 7) == 0)
	{
		query += wordlen;

		query = skip_white_space(query);

		wordlen = 0;
		while (isalpha((unsigned char) query[wordlen]))
			wordlen += PQmblen(&query[wordlen], pset.encoding);

		if (wordlen == 3 && pg_strncasecmp(query, "all", 3) == 0)
			return true;
		return false;
	}

	return false;
}