--- parser3/src/classes/op.C 2012/06/08 11:44:02 1.211 +++ parser3/src/classes/op.C 2015/09/22 23:37:44 1.221 @@ -18,7 +18,7 @@ #include "pa_vclass.h" #include "pa_charset.h" -volatile const char * IDENT_OP_C="$Id: op.C,v 1.211 2012/06/08 11:44:02 misha Exp $"; +volatile const char * IDENT_OP_C="$Id: op.C,v 1.221 2015/09/22 23:37:44 moko Exp $"; // limits @@ -27,9 +27,6 @@ volatile const char * IDENT_OP_C="$Id: o // defines #define CASE_DEFAULT_VALUE "DEFAULT" -#define PROCESS_MAIN_OPTION_NAME "main" -#define PROCESS_FILE_OPTION_NAME "file" -#define PROCESS_LINENO_OPTION_NAME "lineno" // class @@ -145,7 +142,7 @@ static void _taint(Request& r, MethodPar static void _apply_taint(Request& r, MethodParams& params) { String::Language lang=params.count()==1 ? String::L_AS_IS : get_untaint_lang(params.as_string(0, "lang must be string")); const String &sbody=params.as_string(params.count()-1, "body must be string"); - String::Body result_body=sbody.cstr_to_string_body_untaint(lang, 0, &r.charsets); + String::Body result_body=sbody.cstr_to_string_body_untaint(lang, r.connection(false), &r.charsets); r.write_pass_lang(*new String(result_body, String::L_AS_IS)); } @@ -178,24 +175,33 @@ static void _process(Request& r, MethodP const String* main_alias=0; const String* file_alias=0; int line_no_alias_offset=0; + bool allow_class_replace=false; size_t options_index=index+1; if(options_indexget(PROCESS_MAIN_OPTION_NAME)) { - valid_options++; - main_alias=&vmain_alias->as_string(); - } - if(Value* vfile_alias=options->get(PROCESS_FILE_OPTION_NAME)) { - valid_options++; - file_alias=&vfile_alias->as_string(); - } - if(Value* vline_no_alias_offset=options->get(PROCESS_LINENO_OPTION_NAME)) { - valid_options++; - line_no_alias_offset=vline_no_alias_offset->as_int(); + for(HashStringValue::Iterator i(*options); i; i.next() ){ + + String::Body key=i.key(); + Value* value=i.value(); + + if(key == "main") { + valid_options++; + main_alias=&value->as_string(); + } else if(key == "file") { + valid_options++; + file_alias=&value->as_string(); + } else if(key == "lineno") { + valid_options++; + line_no_alias_offset=value->as_int(); + } else if(key == "replace") { + valid_options++; + allow_class_replace=r.process_to_value(*value).as_bool(); + } } - + if(valid_options!=options->count()) throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); } @@ -207,6 +213,9 @@ static void _process(Request& r, MethodP Value& vjunction=params.as_junction(index, "body must be code"); // evaluate source to process const String& source=r.process_to_string(vjunction); + + Temp_class_replace class_replace(r, allow_class_replace); + r.use_buf(*target_class, source.untaint_cstr(String::L_AS_IS, r.connection(false)), main_alias, @@ -288,6 +297,28 @@ static void _while(Request& r, MethodPar static void _use(Request& r, MethodParams& params) { Value& vfile=params.as_no_junction(0, FILE_NAME_MUST_NOT_BE_CODE); + bool allow_class_replace=false; + + if(params.count()==2) + if(HashStringValue* options=params.as_hash(1)) { + int valid_options=0; + for(HashStringValue::Iterator i(*options); i; i.next() ){ + + String::Body key=i.key(); + Value* value=i.value(); + + if(key == "replace") { + valid_options++; + allow_class_replace=r.process_to_value(*value).as_bool(); + } + + if(valid_options!=options->count()) + throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); + } + } + + Temp_class_replace class_replace(r, allow_class_replace); + // _use could be called from the parser3 method only, so caller is always defined r.use_file(r.main_class, vfile.as_string(), r.get_method_filename(&r.get_method_frame()->caller()->method)); } @@ -326,7 +357,7 @@ static void _for(Request& r, MethodParam VInt* vint=new VInt(0); VMethodFrame& caller=*r.get_method_frame()->caller(); - caller.put_element(var_name, vint, false); + r.put_element(caller, var_name, vint); if(delim_maybe_code){ // delimiter set bool need_delim=false; @@ -378,9 +409,6 @@ static void _eval(Request& r, MethodPara } static void _connect(Request& r, MethodParams& params) { -#ifdef RESOURCES_DEBUG -struct timeval mt[2]; -#endif Value& url=params.as_no_junction(0, "url must not be code"); Value& body_code=params.as_junction(1, "body must be code"); @@ -391,27 +419,14 @@ struct timeval mt[2]; } } -#ifdef RESOURCES_DEBUG -//measure:before -gettimeofday(&mt[0],NULL); -#endif // connect SQL_Connection* connection=SQL_driver_manager->get_connection(url.as_string(), protocol2driver_and_client, r.charsets.source().NAME().cstr(), r.request_info.document_root); -#ifdef RESOURCES_DEBUG -//measure:after connect -gettimeofday(&mt[1],NULL); - -double t[2]; -for(int i=0;i<2;i++) - t[i]=mt[i].tv_sec+mt[i].tv_usec/1000000.0; - -r.sql_connect_time+=t[1]-t[0]; -#endif Temp_connection temp_connection(r, connection); + // execute body try { r.process_write(body_code); @@ -451,8 +466,7 @@ public: #endif static void _switch(Request& r, MethodParams& params) { Switch_data* data=new Switch_data(r, r.process_to_value(params[0])); - Temp_hash_value - switch_data_setter(r.classes_conf, switch_data_name, data); + Temp_hash_value, void*> switch_data_setter(&r.classes_conf, switch_data_name, data); Value& cases_code=params.as_junction(1, "switch cases must be code"); // execution of found ^case[...]{code} must be in context of ^switch[...]{code} @@ -541,13 +555,13 @@ static Try_catch_result try_catch(Reques Value* method_frame=junction->method_frame; Value* saved_exception_var_value=method_frame->get_element(exception_var_name); VMethodFrame& frame=*junction->method_frame; - frame.put_element(exception_var_name, &details.vhash, false); + frame.put_element(exception_var_name, &details.vhash); result.processed_code=r.process(*catch_code); // retriving $exception.handled, restoring $exception var Value* vhandled=details.vhash.hash().get(exception_handled_part_name); - frame.put_element(exception_var_name, saved_exception_var_value, false); + frame.put_element(exception_var_name, saved_exception_var_value); bool bhandled=false; if(vhandled) { @@ -632,8 +646,8 @@ static void locked_process_and_cache_put } else throw Exception(PARSER_RUNTIME, result.exception_should_be_handled, - "$"EXCEPTION_VAR_NAME"."EXCEPTION_HANDLED_PART_NAME" value must be " - "either boolean or string '"CACHE_EXCEPTION_HANDLED_CACHE_NAME"'"); + "$" EXCEPTION_VAR_NAME "." EXCEPTION_HANDLED_PART_NAME " value must be " + "either boolean or string '" CACHE_EXCEPTION_HANDLED_CACHE_NAME "'"); } else info.processed_code=&result.processed_code.as_string(); @@ -711,7 +725,7 @@ static time_t as_expires(Request& r, Met int index, time_t now) { time_t result; if(Value* vdate=params[index].as(VDATE_TYPE)) - result=static_cast(vdate)->get_time(); + result=(time_t)(static_cast(vdate)->get_time()); else result=now+(time_t)params.as_double(index, "lifespan must be date or number", r); @@ -725,10 +739,8 @@ static void _cache(Request& r, MethodPar // ^cache[] -- return current expiration time Cache_scope* scope=static_cast(r.classes_conf.get(cache_data_name)); if(!scope) - throw Exception(PARSER_RUNTIME, - 0, - "expire-time get without cache"); - r.write_no_lang(*new VDate(scope->expires)); + throw Exception(PARSER_RUNTIME, 0, "expire-time get without cache"); + r.write_no_lang(*new VDate((pa_time_t)scope->expires)); return; } @@ -763,8 +775,7 @@ static void _cache(Request& r, MethodPar Cache_scope scope={as_expires(r, params, 1, now), 0}; - Temp_hash_value - cache_scope_setter(r.classes_conf, cache_data_name, &scope); + Temp_hash_value, void*> cache_scope_setter(&r.classes_conf, cache_data_name, &scope); Value& body_code=params.as_junction(2, "body_code must be code"); Value* catch_code=0; if(params.count()>3) @@ -907,7 +918,8 @@ VClassMAIN::VClassMAIN(): VClass() { // ^apply-taint[untaint lang][string] add_native_method("apply-taint", Method::CT_ANY, _apply_taint, 1, 2, Method::CO_WITHOUT_FRAME); - // ^process[code] + // ^process{code} + // ^process[context]{code}[options hash] add_native_method("process", Method::CT_ANY, _process, 1, 3); // ^rem{code} @@ -916,8 +928,8 @@ VClassMAIN::VClassMAIN(): VClass() { // ^while(condition){code} add_native_method("while", Method::CT_ANY, _while, 2, 3, Method::CO_WITHOUT_FRAME); - // ^use[file] - add_native_method("use", Method::CT_ANY, _use, 1, 1); + // ^use[file[;options hash]] + add_native_method("use", Method::CT_ANY, _use, 1, 2); // ^break[] add_native_method("break", Method::CT_ANY, _break, 0, 0, Method::CO_WITHOUT_FRAME);