Esempio n. 1
0
// Parse one simple selector, e.g.: `type#id.class1.class2.class3`
SimpleSelector CSSParser::parseSimpleSelector(){
    QString tagName;
    QString id;
    QVector<QString> classes;
    if(!eof()){
        QChar c = peekChar();
        if(c == '#'){
            consumeChar('#');
            id = parseIdentifier();
            qDebug() << "#";
        } else if(c == '.') {
            consumeChar('.');
            classes.append(parseIdentifier());
            qDebug() << ".";
        } else if(c == '*'){
            consumeChar('*');//TODO
            qDebug() << "*";
        } else if(isVaidIdentifier(c)){
            //h1 div.note
            tagName = parseIdentifier();
        }
    }
    SimpleSelector ret{tagName, id, classes};
#ifdef CSS_DEBUG
    qDebug() << Q_FUNC_INFO;
#endif /* CSS_DEBUG */
    return ret;

}
Esempio n. 2
0
//second processor function: takes in a character and checks if it's an asterisk. If not, it just passes the character 
//If so, pulls in another character and check if it's another
//asterisk. If so, it will pass along a carat symbol, if not it just passes both characters. Ends at EOF after passing
//
//Modifier
void *secondproc_thread_func(void *s){
	ThreadInit *i = s;
	/*
 	use a buffer system to check for double-asteriks
	*/
	int c = 0; //if c is not an asterisk, just produce it
	int char_buff = 0;
	int carat = '^'; //convenience
	while(1) {
		//assert there must be at least one full buff if full buffers down passes
		//so read has run at least once and called full buffers up
		c = consumeChar(i);

		if (c == '*'){//if c is a asterisk, get another character to check
			char_buff = consumeChar(i);
			if (char_buff == '*'){
				//we can assert that we know the buffer isn't full
				//by similar logic as the above. This is the only thread that
				//writes to it and if empty buffers passes, output thread function has run
				
				produceChar (i, carat); //if both are asterisks, produce carat
			}
			else{
				produceChar (i, c);		//if only one is asterisk, produce both
				produceChar (i, char_buff);
			}
		}
		else
			produceChar (i, c); //if not asterisks, produce c
		
		if (c == EOF || char_buff == EOF)
			break;
	}
	st_thread_exit(NULL);
}
Esempio n. 3
0
//margin: auto;
Declaration CSSParser::parseDeclaration(){
#ifdef CSS_DEBUG
    qDebug() << Q_FUNC_INFO;
#endif /* CSS_DEBUG */
    QString propertyName = parseIdentifier();
    consumeWhitespaceOrNewline();
    consumeChar(':');
    consumeWhitespaceOrNewline();
    QSharedPointer<Value> value = parseValue();
    consumeWhitespaceOrNewline();
    consumeChar(';');
    Declaration ret{propertyName, value};
    return ret;
}
Esempio n. 4
0
//{ margin: auto; color: #cc0000; }
QVector<Declaration> CSSParser::parseDeclarations(){
    consumeChar('{');
    QVector<Declaration> declarations;
    //    while(peekChar() != '}'){
    //        declarations.append(parseDeclaration());
    //    }

    while (true) {
        consumeWhitespaceOrNewline();
        if (peekChar() == '}') {
            consumeChar();
            break;
        }
        declarations.append(parseDeclaration());
    }
    return declarations;
}
Esempio n. 5
0
static void peekInt(void) {
  current.kind = tINT;

  while (1) {
    const int c = peekChar();
    switch (c) {
      case '0' ... '9':
        consumeChar();
        current.value = current.value * 10 + (c - '0');
        break;
      case '_':
        consumeChar();
        break;
      default:
        return;
    }
  }
}
Esempio n. 6
0
//#aabbcc
QSharedPointer<ColorValue> CSSParser::parseColor(){
#ifdef CSS_DEBUG
    qDebug() << Q_FUNC_INFO;
#endif /* CSS_DEBUG */
    consumeChar('#');
    int r = parseHexPair();
    int g = parseHexPair();
    int b = parseHexPair();
    return QSharedPointer<ColorValue>(new ColorValue(r,g,b, 255));
}
void f(int index) {
  // Should warn.
  // CHECK: fix-it:"{{.*}}":{31:11-31:11}:"&"
  // CHECK: fix-it:"{{.*}}":{31:17-31:18}:"["
  // CHECK: fix-it:"{{.*}}":{31:20-31:20}:"]"
  consume("foo" + 5);  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consume("foo" + index);  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consume("foo" + kMyEnum);  // expected-warning {{adding 'MyEnum' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consume("foo" + kMySmallEnum); // expected-warning {{adding 'MyEnum' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}

  consume(5 + "foo");  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consume(index + "foo");  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consume(kMyEnum + "foo");  // expected-warning {{adding 'MyEnum' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consume(kMySmallEnum + "foo"); // expected-warning {{adding 'MyEnum' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}

  // FIXME: suggest replacing with "foo"[5]
  consumeChar(*("foo" + 5));  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consumeChar(*(5 + "foo"));  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}

  consume(L"foo" + 5);  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consume(L"foo" + 2); // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}

  consume("foo" + 3);  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consume("foo" + 4);  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
  consume("\pfoo" + 4);  // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}

  #define A "foo"
  #define B "bar"
  consume(A B + sizeof(A) - 1); // expected-warning {{to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}

  // Should not warn.
  consume(&("foo"[3]));
  consume(&("foo"[index]));
  consume(&("foo"[kMyEnum]));


  consume("foo" + kMyOperatorOverloadedEnum);
  consume(kMyOperatorOverloadedEnum + "foo");
}
Esempio n. 8
0
QVector<SimpleSelector> CSSParser::parseSimpleSelectors(){
    QVector<SimpleSelector> selectors;
    while (true) {
        consumeWhitespaceOrNewline();
        selectors.append(parseSimpleSelector());
        consumeWhitespaceOrNewline();
        QChar c = peekChar();
        if (c == ',') {
            consumeChar();
        } else if (c == '{') {
            break;
        } else {
            qDebug() << "Illegal character in selector list";
        }
    }
    //todo sort selectors by specificity
    return selectors;

}
Esempio n. 9
0
static void peekId(void) {
  current.kind = tID;

  int len = 0;

  while (1) {
    const int c = peekChar();
    switch (c) {
      case 'a' ... 'z':
      case '0' ... '9':
        consumeChar();
        len++;
        current.ptr = realloc(current.ptr, len + 1);
        current.ptr[len - 1] = c;
        current.ptr[len] = 0;
        break;
      default:
        if (strcmp(current.ptr, "if") == 0) {
          current.kind = tIF;
        } else if (strcmp(current.ptr, "else") == 0) {
          current.kind = tELSE;
        } else if (strcmp(current.ptr, "while") == 0) {
          current.kind = tWHILE;
        } else if (strcmp(current.ptr, "print") == 0) {
          current.kind = tPRINT;
        } else if (strcmp(current.ptr, "fun") == 0) {
          current.kind = tFUN;
        } else if (strcmp(current.ptr, "return") == 0) {
          current.kind = tRETURN;
        } else {
          current.kind = tID;
        }
        if (current.kind != tID) {
          free(current.ptr);
          current.ptr = 0;
        }
        return;
    }
  }
}
Esempio n. 10
0
//the first of the two processing functions: takes in a character in ascii and processes whether the character is a newline
//and if it is, it will pass along a space otherwise it passes the character. Ends on EOF after passing it along
//
//Modifier
void *firstproc_thread_func (void *s){
	ThreadInit *i = s;
	int c = 0;
	int space = 32;
	while(1) {
		//assert there must be at least one full buff if full buffers down passes
		//so read has run at least once and called full buffers up
		c = consumeChar(i);
		//do our processing, pass the space if we meet a newline
		if (c == '\n')
			produceChar(i, space);
		
		//we can assert that we know the buffer isn't full
		//by similar logic as the above. This is the only thread that
		//writes to it and if empty buffers passes, second process thread function has run
		else
			produceChar(i ,c);
		if (c == EOF)
			break;
	}
	st_thread_exit(NULL);
}
Esempio n. 11
0
boost::tribool& RequestParser::consume(Request& req, Buffer::iterator it)
{
  static boost::tribool False(false);
  static boost::tribool True(true);
  static boost::tribool Indeterminate(boost::indeterminate);

  const char input = *it;

  if (++requestSize_ > MAX_REQUEST_HEADER_SIZE)
    return False;

  switch (httpState_)
  {
  case method_start:
    if (input == '\r')
    {
      /*
       * allow a new line before a request -- this seems to be
       * accepted practice when dealing with multiple requests
       * in one connection, separated by a CRLF.
       */
      httpState_ = expecting_newline_0;
      return Indeterminate;
    } else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return False;
    }
    else
    {
      httpState_ = method;
      consumeToString(req.method, MAX_METHOD_SIZE);
      consumeChar(it);
      return Indeterminate;
    }
  case expecting_newline_0:
    if (input == '\n')
    {
      httpState_ = method_start;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case method:
    if (input == ' ')
    {
      consumeComplete(it);
      httpState_ = uri_start;
      return Indeterminate;
    }
    else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return False;
    }
    else
    {
      if (consumeChar(it))
	return Indeterminate;
      else
	return False;
    }
  case uri_start:
    if (is_ctl(input))
    {
      return False;
    }
    else
    {
      httpState_ = uri;
      consumeToString(req.uri, MAX_URI_SIZE);
      consumeChar(it);
      return Indeterminate;
    }
  case uri:
    if (input == ' ')
    {
      consumeComplete(it);

      httpState_ = http_version_h;
      return Indeterminate;
    }
    else if (is_ctl(input))
    {
      return False;
    }
    else
    {
      if (consumeChar(it))
	return Indeterminate;
      else
	return False;
    }
  case http_version_h:
    if (input == 'H')
    {
      httpState_ = http_version_t_1;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_t_1:
    if (input == 'T')
    {
      httpState_ = http_version_t_2;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_t_2:
    if (input == 'T')
    {
      httpState_ = http_version_p;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_p:
    if (input == 'P')
    {
      httpState_ = http_version_slash;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_slash:
    if (input == '/')
    {
      req.http_version_major = 0;
      req.http_version_minor = 0;
      httpState_ = http_version_major_start;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_major_start:
    if (is_digit(input))
    {
      req.http_version_major = req.http_version_major * 10 + input - '0';
      httpState_ = http_version_major;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_major:
    if (input == '.')
    {
      httpState_ = http_version_minor_start;
      return Indeterminate;
    }
    else if (is_digit(input))
    {
      req.http_version_major = req.http_version_major * 10 + input - '0';
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_minor_start:
    if (is_digit(input))
    {
      req.http_version_minor = req.http_version_minor * 10 + input - '0';
      httpState_ = http_version_minor;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_minor:
    if (input == '\r')
    {
      httpState_ = expecting_newline_1;
      return Indeterminate;
    }
    else if (is_digit(input))
    {
      req.http_version_minor = req.http_version_minor * 10 + input - '0';
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case expecting_newline_1:
    if (input == '\n')
    {
      httpState_ = header_line_start;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case header_line_start:
    if (input == '\r')
    {
      httpState_ = expecting_newline_3;
      return Indeterminate;
    }
    else if ((input == ' ' || input == '\t') && haveHeader_)
    {
      // continuation of previous header
      httpState_ = header_lws;
      return Indeterminate;
    }
    else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return False;
    }
    else
    {
      req.headers.push_back(Request::Header());
      haveHeader_ = true;
      consumeToString(req.headers.back().name, MAX_FIELD_NAME_SIZE);
      consumeChar(it);
      httpState_ = header_name;
      return Indeterminate;
    }
  case header_lws:
    if (input == '\r')
    {
      httpState_ = expecting_newline_2;
      return Indeterminate;
    }
    else if (input == ' ' || input == '\t')
    {
      return Indeterminate;
    }
    else if (is_ctl(input))
    {
      return False;
    }
    else
    {
      httpState_ = header_value;
      consumeChar(it);
      return Indeterminate;
    }
  case header_name:
    if (input == ':')
    {
      consumeComplete(it);
      httpState_ = space_before_header_value;
      return Indeterminate;
    }
    else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return False;
    }
    else
    {
      if (consumeChar(it))
	return Indeterminate;
      else
	return False;
    }
  case space_before_header_value:
    if (input == ' ')
    {
      consumeToString(req.headers.back().value, MAX_FIELD_VALUE_SIZE);
      httpState_ = header_value;

      return Indeterminate;
    }
    else
    {
      consumeToString(req.headers.back().value, MAX_FIELD_VALUE_SIZE);
      httpState_ = header_value;

      /* fall through */
    }
  case header_value:
    if (input == '\r')
    {
      consumeComplete(it);

      httpState_ = expecting_newline_2;
      return Indeterminate;
    }
    else if (is_ctl(input))
    {
      return False;
    }
    else
    {
      if (consumeChar(it))
	return Indeterminate;
      else
	return False;
    }
  case expecting_newline_2:
    if (input == '\n')
    {
      httpState_ = header_line_start;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case expecting_newline_3:
    if (input == '\n')
      return True;
    else
      return False;
  default:
    return False;
  }
}
Esempio n. 12
0
static void peek() {
  if (current.kind == tNONE) {
    while (1) {
      current.value = 0;
      current.ptr = 0;

      const int c = peekChar();
      switch (c) {
        case -1:
          current.kind = tEND;
          return;
        case ';':
          consumeChar();
          current.kind = tSEMI;
          return;
        case '0' ... '9':
          peekInt();
          return;
        case 'a' ... 'z':
          peekId();
          return;
        case '(':
          consumeChar();
          current.kind = tLEFT;
          return;
        case ')':
          consumeChar();
          current.kind = tRIGHT;
          return;
        case '{':
          consumeChar();
          current.kind = tLBRACE;
          return;
        case '}':
          consumeChar();
          current.kind = tRBRACE;
          return;
        case '+':
          consumeChar();
          current.kind = tPLUS;
          return;
        case '*':
          consumeChar();
          current.kind = tMUL;
          return;
        case '=':
          consumeChar();
          if (peekChar() == '=') {
            consumeChar();
            current.kind = tEQEQ;
          } else {
            current.kind = tEQ;
          }
          return;
        case '<':
          consumeChar();
          if (peekChar() == '>') {
            consumeChar();
            current.kind = tNE;
          } else {
            current.kind = tLT;
          }
          return;
        case '>':
          consumeChar();
          current.kind = tGT;
          return;
        case ',':
          consumeChar();
          current.kind = tCOMMA;
          return;
        case ' ':
        case 10:
          consumeChar();
          break;
        default:
          printf("undefined char %d\n", c);
          error();
      }
    }
  }
}
Esempio n. 13
0
boost::tribool& RequestParser::consume(Request& req, char input)
{
  static boost::tribool False(false);
  static boost::tribool True(true);
  static boost::tribool Indeterminate(boost::indeterminate);

  if (++requestSize_ > MAX_REQUEST_HEADER_SIZE)
    return False;

  switch (httpState_)
  {
  case method_start:
    if (input == '\r')
    {
      /*
       * allow a new line before a request -- this seems to be
       * accepted practice when dealing with multiple requests
       * in one connection, separated by a CRLF.
       */
      httpState_ = expecting_newline_0;
      return Indeterminate;
    } else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return False;
    }
    else
    {
      httpState_ = method;
      consumeToString(req.method, MAX_METHOD_SIZE);
      consumeChar(input);
      return Indeterminate;
    }
  case expecting_newline_0:
    if (input == '\n')
    {
      httpState_ = method_start;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case method:
    if (input == ' ')
    {
      consumeComplete();
      httpState_ = uri_start;
      return Indeterminate;
    }
    else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return False;
    }
    else
    {
      if (consumeChar(input))
	return Indeterminate;
      else
	return False;
    }
  case uri_start:
    if (is_ctl(input))
    {
      return False;
    }
    else
    {
      httpState_ = uri;
      consumeToString(req.uri, MAX_URI_SIZE);
      consumeChar(input);
      return Indeterminate;
    }
  case uri:
    if (input == ' ')
    {
      consumeComplete();

      httpState_ = http_version_h;
      return Indeterminate;
    }
    else if (is_ctl(input))
    {
      return False;
    }
    else
    {
      if (consumeChar(input))
	return Indeterminate;
      else
	return False;
    }
  case http_version_h:
    if (input == 'H')
    {
      httpState_ = http_version_t_1;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_t_1:
    if (input == 'T')
    {
      httpState_ = http_version_t_2;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_t_2:
    if (input == 'T')
    {
      httpState_ = http_version_p;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_p:
    if (input == 'P')
    {
      httpState_ = http_version_slash;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_slash:
    if (input == '/')
    {
      req.http_version_major = 0;
      req.http_version_minor = 0;
      httpState_ = http_version_major_start;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_major_start:
    if (is_digit(input))
    {
      req.http_version_major = req.http_version_major * 10 + input - '0';
      httpState_ = http_version_major;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_major:
    if (input == '.')
    {
      httpState_ = http_version_minor_start;
      return Indeterminate;
    }
    else if (is_digit(input))
    {
      req.http_version_major = req.http_version_major * 10 + input - '0';
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_minor_start:
    if (is_digit(input))
    {
      req.http_version_minor = req.http_version_minor * 10 + input - '0';
      httpState_ = http_version_minor;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case http_version_minor:
    if (input == '\r')
    {
      httpState_ = expecting_newline_1;
      return Indeterminate;
    }
    else if (is_digit(input))
    {
      req.http_version_minor = req.http_version_minor * 10 + input - '0';
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case expecting_newline_1:
    if (input == '\n')
    {
      httpState_ = header_line_start;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case header_line_start:
    if (input == '\r')
    {
      httpState_ = expecting_newline_3;
      return Indeterminate;
    }
    else if (!req.headerMap.empty() && (input == ' ' || input == '\t'))
    {
      // continuation of previous header
      httpState_ = header_lws;
      return Indeterminate;
    }
    else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return False;
    }
    else
    {
      consumeToString(headerName_, MAX_FIELD_NAME_SIZE);
      consumeChar(input);
      httpState_ = header_name;
      return Indeterminate;
    }
  case header_lws:
    if (input == '\r')
    {
      httpState_ = expecting_newline_2;
      return Indeterminate;
    }
    else if (input == ' ' || input == '\t')
    {
      return Indeterminate;
    }
    else if (is_ctl(input))
    {
      return False;
    }
    else
    {
      httpState_ = header_value;
      headerValue_.push_back(input);
      return Indeterminate;
    }
  case header_name:
    if (input == ':')
    {
      consumeComplete();
      httpState_ = space_before_header_value;
      return Indeterminate;
    }
    else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
    {
      return False;
    }
    else
    {
      if (consumeChar(input))
	return Indeterminate;
      else
	return False;
    }
  case space_before_header_value:
    if (input == ' ')
    {
      consumeToString(headerValue_, MAX_FIELD_VALUE_SIZE);
      httpState_ = header_value;

      return Indeterminate;
    }
    else
    {
      consumeToString(headerValue_, MAX_FIELD_VALUE_SIZE);
      httpState_ = header_value;
    }
  case header_value:
    if (input == '\r')
    {
      consumeComplete();

      if (req.headerMap.find(headerName_) != req.headerMap.end()) {
	req.headerMap[headerName_] += ',' + headerValue_;
      } else {
	Request::HeaderMap::iterator i
	  = req.headerMap.insert(std::make_pair(headerName_, headerValue_))
	    .first;
	req.headerOrder.push_back(i);
      }

      httpState_ = expecting_newline_2;
      return Indeterminate;
    }
    else if (is_ctl(input))
    {
      return False;
    }
    else
    {
      if (consumeChar(input))
	return Indeterminate;
      else
	return False;
    }
  case expecting_newline_2:
    if (input == '\n')
    {
      httpState_ = header_line_start;
      return Indeterminate;
    }
    else
    {
      return False;
    }
  case expecting_newline_3:
    if (input == '\n')
      return True;
    else
      return False;
  default:
    return False;
  }
}
Esempio n. 14
0
GBool PSTokenizer::getToken(char *buf, int size, int *length) {
  GBool comment, backslash;
  int c;
  int i;

  // skip leading whitespace and comments
  comment = gFalse;
  while (1) {
    if ((c = getChar()) == EOF) {
      buf[0] = '\0';
      *length = 0;
      return gFalse;
    }
    if (comment) {
      if (c == '\x0a' || c == '\x0d') {
	comment = gFalse;
      }
    } else if (c == '%') {
      comment = gTrue;
    } else if (specialChars[c] != 1) {
      break;
    }
  }

  // Reserve room for terminating '\0'
  size--;

  // read a token
  i = 0;
  buf[i++] = c;
  if (c == '(') {
    backslash = gFalse;
    while ((c = lookChar()) != EOF) {
      consumeChar();
      if (i < size) {
	buf[i++] = c;
      }
      if (c == '\\') {
	backslash = gTrue;
      } else if (!backslash && c == ')') {
	break;
      } else {
	backslash = gFalse;
      }
    }
  } else if (c == '<') {
    while ((c = lookChar()) != EOF) {
      consumeChar();
      if (i < size && specialChars[c] != 1) {
	buf[i++] = c;
      }
      if (c == '>') {
	break;
      }
    }
  } else if (c != '[' && c != ']') {
    while ((c = lookChar()) != EOF && !specialChars[c]) {
      consumeChar();
      if (i < size) {
	buf[i++] = c;
      }
    }
  }
  // Zero terminate token string
  buf[i] = '\0';
  // Return length of token
  *length = i;

  return gTrue;
}