--- parser3/src/classes/op.C 2003/03/24 13:43:40 1.127.2.22.2.15 +++ parser3/src/classes/op.C 2003/07/24 11:31:20 1.129 @@ -5,7 +5,7 @@ Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char* IDENT_OP_C="$Date: 2003/03/24 13:43:40 $"; +static const char* IDENT_OP_C="$Date: 2003/07/24 11:31:20 $"; #include "classes.h" #include "pa_vmethod_frame.h" @@ -31,7 +31,6 @@ static const char* IDENT_OP_C="$Date: 20 class VClassMAIN: public VClass { public: VClassMAIN(); - override ~VClassMAIN() {} }; // defines for statics @@ -39,10 +38,6 @@ public: #define SWITCH_DATA_NAME "SWITCH-DATA" #define CACHE_DATA_NAME "CACHE-DATA" #define EXCEPTION_VAR_NAME "exception" -#define EXCEPTION_TYPE_PART_NAME "type" -#define EXCEPTION_SOURCE_PART_NAME "source" -#define EXCEPTION_COMMENT_PART_NAME "comment" -#define EXCEPTION_HANDLED_PART_NAME "handled" // statics @@ -52,14 +47,10 @@ static const String switch_data_name(SWI static const String cache_data_name(CACHE_DATA_NAME); static const String exception_var_name(EXCEPTION_VAR_NAME); -static const String exception_type_part_name(EXCEPTION_TYPE_PART_NAME); -static const String exception_source_part_name(EXCEPTION_SOURCE_PART_NAME); -static const String exception_comment_part_name(EXCEPTION_COMMENT_PART_NAME); -static const String exception_handled_part_name(EXCEPTION_HANDLED_PART_NAME); // helpers -class Untaint_lang_name2enum: public Hash { +class Untaint_lang_name2enum: public Hash { public: Untaint_lang_name2enum() { #define ULN(name, LANG) \ @@ -83,25 +74,25 @@ public: // methods -static void _if(Request& r, MethodParams* params) { - Value& condition_code=params->as_junction(0, "condition must be expression"); +static void _if(Request& r, MethodParams& params) { + Value& condition_code=params.as_junction(0, "condition must be expression"); bool condition=r.process_to_value(condition_code, /*0/*no name* /,*/ false/*don't intercept string*/).as_bool(); if(condition) - r.write_pass_lang(r.process(params->as_junction(1, "'then' parameter must be code"))); - else if(params->count()>2) - r.write_pass_lang(r.process(params->as_junction(2, "'else' parameter must be code"))); + r.write_pass_lang(r.process(params.as_junction(1, "'then' parameter must be code"))); + else if(params.count()>2) + r.write_pass_lang(r.process(params.as_junction(2, "'else' parameter must be code"))); } -static void _untaint(Request& r, MethodParams* params) { +static void _untaint(Request& r, MethodParams& params) { String::Language lang; - if(params->count()==1) + if(params.count()==1) lang=String::L_AS_IS; // mark as simply 'tainted'. useful in html from sql else { - const String& lang_name=params->as_string(0, "lang must be string"); + const String& lang_name=params.as_string(0, "lang must be string"); lang=untaint_lang_name2enum.get(lang_name); if(!lang) throw Exception(0, @@ -110,19 +101,19 @@ static void _untaint(Request& r, MethodP } { - Value& vbody=params->as_junction(params->count()-1, "body must be code"); + Value& vbody=params.as_junction(params.count()-1, "body must be code"); Temp_lang temp_lang(r, lang); // set temporarily specified ^untaint[language; r.write_pass_lang(r.process(vbody)); // process marking tainted with that lang } } -static void _taint(Request& r, MethodParams* params) { +static void _taint(Request& r, MethodParams& params) { String::Language lang; - if(params->count()==1) + if(params.count()==1) lang=String::L_TAINTED; // mark as simply 'tainted'. useful in table:set else { - const String& lang_name=params->as_string(0, "lang must be string"); + const String& lang_name=params.as_string(0, "lang must be string"); lang=untaint_lang_name2enum.get(lang_name); if(!lang) throw Exception(0, @@ -131,7 +122,7 @@ static void _taint(Request& r, MethodPar } { - Value& vbody=params->as_no_junction(params->count()-1, "body must not be code"); + Value& vbody=params.as_no_junction(params.count()-1, "body must not be code"); String result; result.append( @@ -141,22 +132,24 @@ static void _taint(Request& r, MethodPar } } -static void _process(Request& r, MethodParams* params) { +static void _process(Request& r, MethodParams& params) { Method* main_method; - Value& target_self=params->count()>1? - params->as_no_junction(0, "target must not be code") - :r.get_method_frame()->caller()->self(); - { - Value& vjunction=params->as_junction(params->count()-1, "body must be code"); - VStateless_class *target_class=target_self.get_last_derived_class(); + size_t index=0; + Value* target_self; + Value& maybe_target_self=params[index]; + if(maybe_target_self.get_string() || maybe_target_self.get_junction()) + target_self=&r.get_method_frame()->caller()->self(); + else { + target_self=&maybe_target_self; index++; + } + + { + VStateless_class *target_class=target_self->get_last_derived_class(); if(!target_class) throw Exception("parser.runtime", 0, "no target class"); - - // evaluate source to process - const String& source=r.process_to_string(vjunction); // temporary remove language change Temp_lang temp_lang(r, String::L_PASS_APPENDED); @@ -164,34 +157,24 @@ static void _process(Request& r, MethodP Temp_method temp_method_main(*target_class, main_method_name, 0); // temporary zero @auto so it wouldn't be auto-called in Request::use_buf Temp_method temp_method_auto(*target_class, auto_method_name, 0); -#ifdef LATER - // calculate pseudo file name of processed chars - // would be something like "/some/file(4) process" - char local_place[MAX_STRING]; -#ifndef NO_STRING_ORIGIN - const String_fragment::Origin& source_origin=source->origin(); - const String_fragment::Origin& method_origin=method_name->origin(); - size_t place_size; - if(source_origin.file==method_origin.file) - place_size=snprintf(local_place, MAX_STRING, "%s(%d) %s", // same file - source_origin.file?source_origin.file:"unknown_file", 1+source_origin.line, - method_name->cstr().get())+1; - else // different files ^process{external__file_text__or__sql} - place_size=snprintf(local_place, MAX_STRING, "%s", - source_origin.file?source_origin.file:"unknown_file")+1; -#else - strncpy(local_place, method_name->cstr(), MAX_STRING-1); place[MAX_STRING-1]=0; - size_t place_size=strlen(local_place)+1; -#endif - char *heap_place=pool.copy(local_place, place_size); -#endif - // process source code, append processed methods to 'self' class - // maybe-define new @main - r.use_buf(*target_class, - source.cstr(String::L_UNSPECIFIED, r.connection()), - *new String("later"), //new String(heap_place, place_size, true /*tainted*/), - "later"); //heap_place); - + + size_t main_alias_index=index+1; + const String* main_alias=0; + if(main_alias_indexget_method(main_method_name); } @@ -199,19 +182,19 @@ static void _process(Request& r, MethodP // maybe-execute @main[] if(main_method) { // temporarily set method_frame's self to target_self - Temp_method_frame_self tmfs(*r.get_method_frame(), target_self); + Temp_method_frame_self tmfs(*r.get_method_frame(), *target_self); // execute! r.execute(*main_method->parser_code); } } -static void _rem(Request& r, MethodParams* params) { - params->as_junction(0, "body must be code"); +static void _rem(Request& r, MethodParams& params) { + params.as_junction(0, "body must be code"); } -static void _while(Request& r, MethodParams* params) { - Value& vcondition=params->as_junction(0, "condition must be expression"); - Value& body=params->as_junction(1, "body must be code"); +static void _while(Request& r, MethodParams& params) { + Value& vcondition=params.as_junction(0, "condition must be expression"); + Value& body=params.as_junction(1, "body must be code"); // while... int endless_loop_count=0; @@ -232,17 +215,17 @@ 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"); +static void _use(Request& r, MethodParams& params) { + Value& vfile=params.as_no_junction(0, "file name must not be code"); r.use_file(r.main_class, vfile.as_string()); } -static void _for(Request& r, MethodParams* params) { - const String& var_name=params->as_string(0, "var name must be string"); - int from=params->as_int(1, "from must be int", r); - int to=params->as_int(2, "to must be int", r); - Value& body_code=params->as_junction(3, "body must be code"); - Value* delim_maybe_code=params->count()>4?(*params)[4]:0; +static void _for(Request& r, MethodParams& params) { + const String& var_name=params.as_string(0, "var name must be string"); + int from=params.as_int(1, "from must be int", r); + int to=params.as_int(2, "to must be int", r); + Value& body_code=params.as_junction(3, "body must be code"); + Value* delim_maybe_code=params.count()>4?¶ms[4]:0; if(to-from>=MAX_LOOPS) // too long loop? throw Exception("parser.runtime", @@ -266,25 +249,25 @@ static void _for(Request& r, MethodParam } } -static void _eval(Request& r, MethodParams* params) { - Value& expr=params->as_junction(0, "need expression"); +static void _eval(Request& r, MethodParams& params) { + Value& expr=params.as_junction(0, "need expression"); // evaluate expresion - Value& value_result=*r.process_to_value(expr, + Value& value_result=r.process_to_value(expr, /*0/*no name YET* /,*/ true/*don't intercept string*/).as_expr_result(); - if(params->count()>1) { - Value& fmt=params->as_no_junction(1, "fmt must not be code"); + if(params.count()>1) { + Value& fmt=params.as_no_junction(1, "fmt must not be code"); r.write_no_lang(String(format(value_result.as_double(), fmt.as_string().cstrm()))); } else r.write_no_lang(value_result); } -static void _connect(Request& r, MethodParams* params) { +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"); + Value& url=params.as_no_junction(0, "url must not be code"); + Value& body_code=params.as_junction(1, "body must be code"); Table* protocol2driver_and_client=0; if(Value* sql=r.main_class.get_element(String(MAIN_SQL_NAME), r.main_class, false)) { @@ -315,9 +298,12 @@ r.sql_connect_time+=t[1]-t[0]; // execute body try { r.write_assign_lang(r.process(body_code)); + connection->commit(); + connection->close(); } catch(...) { // process problem - connection->mark_to_rollback(); - rethrow; + connection->rollback(); + connection->close(); + rethrow; } } @@ -333,12 +319,12 @@ public: r(ar), searching(asearching) {} }; #endif -static void _switch(Request& r, MethodParams* params) { - Switch_data* data=new Switch_data(r, r.process_to_value(*(*params)[0])); +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); - Value& cases_code=params->as_junction(1, "switch cases must be code"); + Value& cases_code=params.as_junction(1, "switch cases must be code"); // execution of found ^case[...]{code} must be in context of ^switch[...]{code} // because of stacked WWrapper used there as wcontext r.process(cases_code, true/*intercept_string*/); @@ -349,22 +335,22 @@ static void _switch(Request& r, MethodPa } } -static void _case(Request& r, MethodParams* params) { +static void _case(Request& r, MethodParams& params) { Switch_data* data=static_cast(r.classes_conf.get(switch_data_name)); if(!data) throw Exception("parser.runtime", 0, "without switch"); - int count=params->count(); - Value& code=params->as_junction(--count, "case result must be code"); + int count=params.count(); + Value& code=params.as_junction(--count, "case result must be code"); // killing context for safety, would execute in ^switch[...]{>>context<<} // reason: context is stacked, and it would become invalid afterwards //code->get_junction()->change_context(0); for(int i=0; i_default=&code; @@ -413,7 +399,6 @@ class Cache_data: public PA_Object { public: time_t expires; }; -DECLARE_OBJECT_PTR(Cache_data); struct Locked_process_and_cache_put_action_info { Request *r; Cache_data *data; @@ -434,7 +419,7 @@ static void locked_process_and_cache_put // expiration time not spoiled by ^cache(0) or something? if(info.data->expires > time(0)) { // string -serialize> buffer - String::C serialized=info.evaluated_body->serialize( + String::Cm serialized=info.evaluated_body->serialize( sizeof(Data_string_serialized_prolog)); Data_string_serialized_prolog& prolog= *reinterpret_cast(serialized.str); @@ -450,7 +435,7 @@ const String* locked_process_and_cache_p Value& body_code, Cache_data& data, const String& file_spec) { - Locked_process_and_cache_put_action_info info; + Locked_process_and_cache_put_action_info info={0}; info.r=&r; info.data=&data; info.body_code=&body_code; @@ -467,8 +452,8 @@ const String* locked_process_and_cache_p cache_delete(file_spec); return result; } -const String* cache_get(Charset& charset, const String& file_spec, time_t now) { - File_read_result file=file_read(charset, file_spec, +const String* cache_get(Request_charsets& charsets, const String& file_spec, time_t now) { + File_read_result file=file_read(charsets, file_spec, false/*as_text*/, 0, //no params false/*fail_on_read_problem*/); @@ -489,25 +474,25 @@ const String* cache_get(Charset& charset return 0; } -static time_t as_expires(Request& r, MethodParams* params, +static time_t as_expires(Request& r, MethodParams& params, int index, time_t now) { time_t result; - if(Value* vdate=(*params)[index]->as(VDATE_TYPE, false)) + if(Value* vdate=params[index].as(VDATE_TYPE, false)) result=static_cast(vdate)->get_time(); else - result=now+(time_t)params->as_double(index, "lifespan must be date or number", r); + result=now+(time_t)params.as_double(index, "lifespan must be date or number", r); return result; } -static const String& as_file_spec(Request& r, MethodParams* params, int index) { - return r.absolute(params->as_string(index, "filespec must be string")); +static const String& as_file_spec(Request& r, MethodParams& params, int index) { + return r.absolute(params.as_string(index, "filespec must be string")); } -static void _cache(Request& r, MethodParams* params) { +static void _cache(Request& r, MethodParams& params) { time_t now=time(0); // ^cache[filename] ^cache(seconds) ^cache[expires date] - if(params->count()==1) { - if((*params)[0]->is_string()) { // filename? + if(params.count()==1) { + if(params[0].is_string()) { // filename? cache_delete(as_file_spec(r, params, 0)); return; } @@ -527,13 +512,13 @@ static void _cache(Request& r, MethodPar } // file_spec, expires, body code - const String& file_spec=r.absolute(params->as_string(0, "filespec must be string")); + const String& file_spec=r.absolute(params.as_string(0, "filespec must be string")); Cache_data* data=new Cache_data; Temp_hash_value cache_data_setter(r.classes_conf, cache_data_name, data); data->expires=as_expires(r, params, 1, now); - Value& body_code=params->as_junction(2, "body must be code"); + Value& body_code=params.as_junction(2, "body must be code"); if(data->expires>now) { // valid 'expires' specified? try cached copy... // hence we don't hope to have unary create/lockEX @@ -553,7 +538,7 @@ static void _cache(Request& r, MethodPar // |lockSH succeeds; ... for(int retry=0; retry<2; retry++) { - if(const String* cached_body=cache_get(r.charsets.source(), file_spec, now)) { // have cached copy? + if(const String* cached_body=cache_get(r.charsets, file_spec, now)) { // have cached copy? // write it out r.write_assign_lang(*cached_body); // happy with it @@ -588,29 +573,13 @@ static void _cache(Request& r, MethodPar // never reached } -// also used in pa_request.C to pass param to @unhandled_exception -VHash& exception2vhash(const Exception& e) { - VHash& result=*new VHash; - HashStringValue& hash=result.hash(); - if(const char* type=e.type(true)) - hash.put(exception_type_part_name, new VString(*new String(type))); - if(const String* asource=e.problem_source()) { - String& source=*new String; - source.append(*asource, String::L_TAINTED, true/*forced*/); - - hash.put(exception_source_part_name, new VString(source)); - } - if(const char* comment=e.comment(true)) - hash.put(exception_comment_part_name, - new VString(*new String(comment, 0, true/*tainted*/))); - hash.put(exception_handled_part_name, new VBool(false)); - return result; -} -static void _try_operator(Request& r, MethodParams* params) { - Value& body_code=params->as_junction(0, "body_code must be code"); - Value& catch_code=params->as_junction(1, "catch_code must be code"); +// also used in pa_request.C to pass param to @unhandled_exception + +static void _try_operator(Request& r, MethodParams& params) { + Value& body_code=params.as_junction(0, "body_code must be code"); + Value& catch_code=params.as_junction(1, "catch_code must be code"); StringOrValue result; // taking snapshot of try-context @@ -618,35 +587,34 @@ static void _try_operator(Request& r, Me try { result=r.process(body_code); } catch(const Exception& e) { + Request::Exception_details details=r.get_details(e); + Request_context_saver throw_context(r); // taking snapshot of throw-context [stack trace contains error] try_context.restore(); // restoring try-context to perform catch-code - VHash& vhash=exception2vhash(e); - Junction* junction=catch_code.get_junction(); Value* method_frame=junction->method_frame; Value* saved_exception_var_value=method_frame->get_element(exception_var_name, *method_frame, false); - junction->method_frame->put_element(exception_var_name, &vhash, false); + junction->method_frame->put_element(exception_var_name, &details.vhash, false); result=r.process(catch_code); bool handled=false; if(Value* value= - vhash.hash().get(exception_handled_part_name)) + details.vhash.hash().get(exception_handled_part_name)) handled=value->as_bool(); junction->method_frame->put_element(exception_var_name, saved_exception_var_value, false); if(!handled) { throw_context.restore(); // restoring throw-context [exception were not handled] - throw(e); // rethrow + rethrow; } } // write out result r.write_pass_lang(result); } -static void _throw_operator(Request& r, MethodParams* params) { - if(params->count()==1) { - Value* param0=(*params)[0]; - if(HashStringValue *hash=param0->get_hash()) { +static void _throw_operator(Request& r, MethodParams& params) { + if(params.count()==1) { + if(HashStringValue *hash=params[0].get_hash()) { const char* type=0; if(Value* value=hash->get(exception_type_part_name)) type=value->as_string().cstr(); @@ -665,9 +633,9 @@ static void _throw_operator(Request& r, 0, "one-param version has hash param"); } else { - const char* type=params->as_string(0, "type must be string").cstr(); - const String& source=params->as_string(1, "source must be string"); - const char* comment=params->count()>2? params->as_string(2, "comment must be string").cstr() + const char* type=params.as_string(0, "type must be string").cstr(); + const String& source=params.as_string(1, "source must be string"); + const char* comment=params.count()>2? params.as_string(2, "comment must be string").cstr() :0; throw Exception(type, &source, "%s", comment?comment:""); } @@ -675,7 +643,7 @@ static void _throw_operator(Request& r, #if defined(WIN32) && defined(_DEBUG) # define PA_BPT -static void _bpt(Request& r, MethodParams* params) { +static void _bpt(Request& r, MethodParams& params) { _asm int 3; } #endif @@ -748,6 +716,5 @@ VClassMAIN::VClassMAIN(): VClass() { // constructor & configurator VStateless_class& VClassMAIN_create() { - return *new VClassMAIN; }