void sinsp_filter::compile(const string& fltstr) { m_fltstr = fltstr; m_scansize = (uint32_t)m_fltstr.size(); while(true) { char a = next(); switch(a) { case 0: // // Finished parsing the filter string // if(m_nest_level != 0) { throw sinsp_exception("filter error: unexpected end of filter"); } if(m_state != ST_EXPRESSION_DONE) { throw sinsp_exception("filter error: unexpected end of filter at position " + to_string((long long) m_scanpos)); } // // Good filter // return; break; case '(': if(m_state != ST_NEED_EXPRESSION) { throw sinsp_exception("unexpected '(' after " + m_fltstr.substr(0, m_scanpos)); } push_expression(m_last_boolop); break; case ')': pop_expression(); break; case 'o': if(next() == 'r') { m_last_boolop = BO_OR; } else { throw sinsp_exception("syntax error in filter at position " + to_string((long long) m_scanpos)); } if(m_state != ST_EXPRESSION_DONE) { throw sinsp_exception("unexpected 'or' after " + m_fltstr.substr(0, m_scanpos)); } m_state = ST_NEED_EXPRESSION; break; case 'a': if(next() == 'n' && next() == 'd') { m_last_boolop = BO_AND; } else { throw sinsp_exception("syntax error in filter at position " + to_string((long long) m_scanpos)); } if(m_state != ST_EXPRESSION_DONE) { throw sinsp_exception("unexpected 'and' after " + m_fltstr.substr(0, m_scanpos)); } m_state = ST_NEED_EXPRESSION; break; case 'n': if(next() == 'o' && next() == 't') { m_last_boolop = (boolop)((uint32_t)m_last_boolop | BO_NOT); } else { throw sinsp_exception("syntax error in filter at position " + to_string((long long) m_scanpos)); } if(m_state != ST_EXPRESSION_DONE && m_state != ST_NEED_EXPRESSION) { throw sinsp_exception("unexpected 'not' after " + m_fltstr.substr(0, m_scanpos)); } m_state = ST_NEED_EXPRESSION; break; default: parse_check(m_curexpr, m_last_boolop); m_state = ST_EXPRESSION_DONE; break; } } vector<string> components = sinsp_split(m_fltstr, ' '); }
void sinsp_filter::parse_check(sinsp_filter_expression* parent_expr, boolop op) { uint32_t startpos = m_scanpos; vector<char> operand1 = next_operand(true, false); string str_operand1 = string((char *)&operand1[0]); sinsp_filter_check* chk = g_filterlist.new_filter_check_from_fldname(str_operand1, m_inspector, true); if(chk == NULL) { throw sinsp_exception("filter error: unrecognized field " + str_operand1 + " at pos " + to_string((long long) startpos)); } if(m_ttable_only) { if(!(chk->get_fields()->m_flags & filter_check_info::FL_WORKS_ON_THREAD_TABLE)) { throw sinsp_exception("the given filter is not supported for thread table filtering"); } } ppm_cmp_operator co = next_comparison_operator(); chk->m_boolop = op; chk->m_cmpop = co; chk->parse_field_name((char *)&operand1[0], true); // // In this case we need to create '(field=value1 or field=value2 ...)' // if(co == CO_IN) { // // Separate the 'or's from the // rest of the conditions // push_expression(op); // // Skip spaces // if(isblank(m_fltstr[m_scanpos])) { next(); } if(m_fltstr[m_scanpos] != '(') { throw sinsp_exception("expected '(' after 'in' operand"); } // // Skip '(' // m_scanpos++; // // The first boolean operand will be BO_NONE // Then we will start putting BO_ORs // op = BO_NONE; // // Create the 'or' sequence // while(true) { // 'in' clause aware vector<char> operand2 = next_operand(false, true); // // Append every sinsp_filter_check creating the 'or' sequence // sinsp_filter_check* newchk = g_filterlist.new_filter_check_from_another(chk); newchk->m_boolop = op; newchk->m_cmpop = CO_EQ; newchk->parse_filter_value((char *)&operand2[0], (uint32_t)operand2.size() - 1); // // We pushed another expression before // so 'parent_expr' still referers to // the old one, this is the new nested // level for the 'or' sequence // m_curexpr->add_check(newchk); next(); if(m_fltstr[m_scanpos] == ')') { break; } else if(m_fltstr[m_scanpos] == ',') { m_scanpos++; } else { throw sinsp_exception("expected either ')' or ',' after a value inside the 'in' clause"); } // // From now on we 'or' every newchk // op = BO_OR; } // // Come back to the rest of the filter // pop_expression(); } else { // // In this case we want next() to return the very next character // At this moment m_scanpos is already at it // e.g. "(field exists) and ..." // if(co == CO_EXISTS) { m_scanpos--; } // // Otherwise we need a value for the operand // else { vector<char> operand2 = next_operand(false, false); chk->parse_filter_value((char *)&operand2[0], (uint32_t)operand2.size() - 1); } parent_expr->add_check(chk); } }