// 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; }
//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); }
//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; }
//{ 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; }
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; } } }
//#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"); }
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; }
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; } } }
//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); }
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; } }
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(); } } } }
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; } }
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; }