|
|
| version 1.37, 2006/04/09 13:38:46 | version 1.47, 2009/06/14 00:33:36 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: @b hashfile parser class. | Parser: @b hashfile parser class. |
| Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| */ | */ |
| Line 18 static const char * const IDENT="$Id$"; | Line 18 static const char * const IDENT="$Id$"; |
| class MHashfile : public Methoded { | class MHashfile : public Methoded { |
| public: // VStateless_class | public: // VStateless_class |
| Value *create_new_value(Pool& apool, HashStringValue&) { return new VHashfile(apool); } | Value *create_new_value(Pool& apool, HashStringValue*) { return new VHashfile(apool); } |
| public: | public: |
| MHashfile(); | MHashfile(); |
| Line 40 extern String cycle_data_name; | Line 40 extern String cycle_data_name; |
| // methods | // methods |
| typedef Hash<const String::Body, bool> HashStringBool; | typedef HashString<bool> HashStringBool; |
| static void _open(Request& r, MethodParams& params) { | static void _open(Request& r, MethodParams& params) { |
| HashStringBool* file_list=static_cast<HashStringBool*>(r.classes_conf.get(OPEN_DATA_NAME)); | HashStringBool* file_list=static_cast<HashStringBool*>(r.classes_conf.get(OPEN_DATA_NAME)); |
| Line 49 static void _open(Request& r, MethodPara | Line 49 static void _open(Request& r, MethodPara |
| r.classes_conf.put(OPEN_DATA_NAME, file_list); | r.classes_conf.put(OPEN_DATA_NAME, file_list); |
| } | } |
| const String& file_spec=r.absolute(params.as_string(0, "filename must be string")); | const String& file_spec=r.absolute(params.as_string(0, FILE_NAME_MUST_BE_STRING)); |
| if(file_list->get(file_spec)) | if(file_list->get(file_spec)) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "this hashfile is already opened, use existing variable"); | "this hashfile is already opened, use existing variable"); |
| file_list->put(file_spec, true); | file_list->put(file_spec, true); |
| Line 84 static void _delete(Request& r, MethodPa | Line 84 static void _delete(Request& r, MethodPa |
| static void _clear(Request& r, MethodParams&) { | static void _clear(Request& r, MethodParams&) { |
| VHashfile& self=GET_SELF(r, VHashfile); | VHashfile& self=GET_SELF(r, VHashfile); |
| self.clear(); | self.delete_files(); |
| } | } |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| Line 101 struct Foreach_info { | Line 101 struct Foreach_info { |
| bool need_delim; | bool need_delim; |
| }; | }; |
| #endif | #endif |
| static bool one_foreach_cycle(const String::Body key, const String& value, void* ainfo) { | static bool one_foreach_cycle( |
| const String::Body key, | |
| const String& value, | |
| void* ainfo) { | |
| Foreach_info& info=*static_cast<Foreach_info*>(ainfo); | Foreach_info& info=*static_cast<Foreach_info*>(ainfo); |
| info.vkey->set_string(*new String(key, String::L_TAINTED)); | if(info.key_var_name){ |
| info.vvalue->set_string(value); | info.vkey->set_string(*new String(key, String::L_TAINTED)); |
| info.var_context->put_element(*info.var_context, *info.key_var_name, info.vkey, false); | info.var_context->put_element(*info.var_context, *info.key_var_name, info.vkey, false); |
| info.var_context->put_element(*info.var_context, *info.value_var_name, info.vvalue, false); | } |
| if(info.value_var_name){ | |
| info.vvalue->set_string(value); | |
| info.var_context->put_element(*info.var_context, *info.value_var_name, info.vvalue, false); | |
| } | |
| StringOrValue sv_processed=info.r->process(*info.body_code); | StringOrValue sv_processed=info.r->process(*info.body_code); |
| Request::Skip lskip=info.r->get_skip(); info.r->set_skip(Request::SKIP_NOTHING); | Request::Skip lskip=info.r->get_skip(); info.r->set_skip(Request::SKIP_NOTHING); |
| const String* s_processed=sv_processed.get_string(); | const String* s_processed=sv_processed.get_string(); |
| if(info.delim_maybe_code && s_processed && s_processed->length()) { // delimiter set and we have body | if(info.delim_maybe_code && s_processed && !s_processed->is_empty()) { // delimiter set and we have body |
| if(info.need_delim) // need delim & iteration produced string? | if(info.need_delim) // need delim & iteration produced string? |
| info.r->write_pass_lang(info.r->process(*info.delim_maybe_code)); | info.r->write_pass_lang(info.r->process(*info.delim_maybe_code)); |
| info.need_delim=true; | else |
| info.need_delim=true; | |
| } | } |
| info.r->write_pass_lang(sv_processed); | info.r->write_pass_lang(sv_processed); |
| return lskip==Request::SKIP_BREAK; | return lskip==Request::SKIP_BREAK; |
| Line 124 static void _foreach(Request& r, MethodP | Line 134 static void _foreach(Request& r, MethodP |
| Temp_hash_value<const String::Body, void*> | Temp_hash_value<const String::Body, void*> |
| cycle_data_setter(r.classes_conf, cycle_data_name, /*any not null flag*/&r); | cycle_data_setter(r.classes_conf, cycle_data_name, /*any not null flag*/&r); |
| const String& key_var_name=params.as_string(0, "key-var name must be string"); | |
| const String& value_var_name=params.as_string(1, "value-var name must be string"); | |
| Foreach_info info={ | |
| &r, | |
| key_var_name.is_empty()? 0 : &key_var_name, | |
| value_var_name.is_empty()? 0 : &value_var_name, | |
| ¶ms.as_junction(2, "body must be code"), | |
| /*delimiter*/params.count()>3 ? params.get(3) : 0, | |
| /*var_context*/r.get_method_frame()->caller(), | |
| /*vkey=*/new VString, | |
| /*vvalue=*/new VString, | |
| false | |
| }; | |
| VHashfile& self=GET_SELF(r, VHashfile); | VHashfile& self=GET_SELF(r, VHashfile); |
| self.for_each(one_foreach_cycle, &info); | |
| } | |
| Foreach_info info; | static bool one_cleanup_cycle(const String::Body, const String&, void*) { |
| return false; | |
| info.r=&r; | } |
| info.key_var_name=¶ms.as_string(0, "key-var name must be string"); | static void _cleanup(Request& r, MethodParams&) { |
| info.value_var_name=¶ms.as_string(1, "value-var name must be string"); | VHashfile& self=GET_SELF(r, VHashfile); |
| info.body_code=¶ms.as_junction(2, "body must be code"); | |
| info.delim_maybe_code=params.count()>3?params.get(3):0; | |
| info.var_context=info.body_code->get_junction()->wcontext; | |
| info.vkey=new VString; | |
| info.vvalue=new VString; | |
| info.need_delim=false; | self.for_each(one_cleanup_cycle, 0); |
| } | |
| self.for_each(one_foreach_cycle, &info); | static void _release(Request& r, MethodParams&) { |
| VHashfile& self=GET_SELF(r, VHashfile); | |
| self.close(); | |
| } | } |
| // constructor | // constructor |
| MHashfile::MHashfile(): Methoded("hashfile") { | MHashfile::MHashfile(): Methoded("hashfile") { |
| // ^hashfile::open[db_home;filename] | // ^hashfile::open[filename] |
| add_native_method("open", Method::CT_DYNAMIC, _open, 1, 1); | add_native_method("open", Method::CT_DYNAMIC, _open, 1, 1); |
| // ^hash[] | // ^hashfile.hash[] |
| add_native_method("hash", Method::CT_DYNAMIC, _hash, 0, 0); | add_native_method("hash", Method::CT_DYNAMIC, _hash, 0, 0); |
| // ^hashfile.delete[key] | // ^hashfile.delete[key] |
| add_native_method("delete", Method::CT_DYNAMIC, _delete, 0, 1); | add_native_method("delete", Method::CT_DYNAMIC, _delete, 0, 1); |
| // ^hashfile.clear[] | // ^hashfile.clear[] -- for backward compatibility. use .delete[] instead. |
| add_native_method("clear", Method::CT_DYNAMIC, _clear, 0, 0); | add_native_method("clear", Method::CT_DYNAMIC, _clear, 0, 0); |
| // ^hashfile.release[] | |
| add_native_method("release", Method::CT_DYNAMIC, _release, 0, 0); | |
| // ^hashfile.cleanup[] | |
| add_native_method("cleanup", Method::CT_DYNAMIC, _cleanup, 0, 0); | |
| add_native_method("defecate", Method::CT_DYNAMIC, _cleanup, 0, 0); | |
| // ^hashfile.foreach[key;value]{code}[delim] | // ^hashfile.foreach[key;value]{code}[delim] |
| add_native_method("foreach", Method::CT_DYNAMIC, _foreach, 2+1, 2+1+1); | add_native_method("foreach", Method::CT_DYNAMIC, _foreach, 2+1, 2+1+1); |
| } | } |