|
|
| version 1.1, 2001/10/22 12:30:24 | version 1.68, 2025/05/26 01:56:54 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: @b hashfile parser class. | Parser: @b hashfile parser class. |
| Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2024 Art. Lebedev Studio (http://www.artlebedev.com) |
| Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf) | Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru> |
| $Id$ | |
| */ | */ |
| #include "pa_config_includes.h" | |
| #ifdef HAVE_LIBDB | |
| #include "classes.h" | #include "classes.h" |
| #include "pa_request.h" | #include "pa_request.h" |
| #include "pa_vmethod_frame.h" | |
| #include "pa_vhashfile.h" | #include "pa_vhashfile.h" |
| #include "pa_vhash.h" | #include "pa_vhash.h" |
| // defines | volatile const char * IDENT_HASHFILE_C="$Id$"; |
| #define HASH_CLASS_NAME "hashfile" | |
| // class | // class |
| class MHashfile : public Methoded { | class MHashfile : public Methoded { |
| public: // VStateless_class | public: // VStateless_class |
| Value *create_new_value(Pool& pool) { return new(pool) VHashfile(pool); } | Value *create_new_value(Pool& apool) { return new VHashfile(apool); } |
| public: | public: |
| MHashfile(Pool& pool); | MHashfile(); |
| public: // Methoded | |
| bool used_directly() { return true; } | |
| }; | }; |
| // global variable | |
| DECLARE_CLASS_VAR(hashfile, new MHashfile); | |
| // defines for statics | |
| #define OPEN_DATA_NAME "HASHFILE-OPEN-DATA" | |
| // methods | // methods |
| static void _assign(Request& r, const String& method_name, MethodParams *params) { | typedef HashString<bool> HashStringBool; |
| Pool& pool=r.pool(); | |
| VHashfile& self=*static_cast<VHashfile *>(r.self); | static void _open(Request& r, MethodParams& params) { |
| HashStringBool* file_list=static_cast<HashStringBool*>(r.classes_conf.get(OPEN_DATA_NAME)); | |
| if(!file_list) { | |
| file_list=new HashStringBool(); | |
| r.classes_conf.put(OPEN_DATA_NAME, file_list); | |
| } | |
| const String& file_spec=r.full_disk_path(params.as_file_name(0)); | |
| if(file_list->get(file_spec)) | |
| throw Exception(PARSER_RUNTIME, | |
| 0, | |
| "this hashfile is already opened, use existing variable"); | |
| file_list->put(file_spec, true); | |
| VHashfile& self=GET_SELF(r, VHashfile); | |
| self.open(file_spec); | |
| } | |
| static void _hash(Request& r, MethodParams&) { | |
| VHashfile& self=GET_SELF(r, VHashfile); | |
| const String &sfile_spec=params->as_string(0, "filename must be string"); | // write out result |
| VHash& result=*new VHash(*self.get_hash()); | |
| r.write(result); | |
| } | |
| self.set_file_spec(r.absolute(sfile_spec)); | static void _delete(Request& r, MethodParams& params) { |
| VHashfile& self=GET_SELF(r, VHashfile); | |
| if(!params.count()) { | |
| // ^hashfile.delete[] asked to delete hashfile itself | |
| self.delete_files(); | |
| return; | |
| } | |
| // key | |
| const String &key=params.as_string(0, "key must be string"); | |
| // remove | |
| self.remove(key); | |
| } | } |
| //static_cast<VHashfile *>(r.self) const String& file_spec=->file_spec(); | |
| // constructor | static void _clear(Request& r, MethodParams&) { |
| VHashfile& self=GET_SELF(r, VHashfile); | |
| self.delete_files(); | |
| } | |
| MHashfile::MHashfile(Pool& apool) : Methoded(apool) { | #ifndef DOXYGEN |
| set_name(*NEW String(pool(), HASH_CLASS_NAME)); | struct Foreach_info { |
| Request* r; | |
| const String* key_var_name; | |
| const String* value_var_name; | |
| Value* body_code; | |
| Value* delim_maybe_code; | |
| // ^hashfile::assign[filename] | Value* var_context; |
| add_native_method("assign", Method::CT_DYNAMIC, _assign, 1, 1); | bool need_delim; |
| /* | }; |
| // ^hashfile.delete[key] | #endif |
| add_native_method("delete", Method::CT_DYNAMIC, _delete, 1, 1); | static bool one_foreach_cycle( |
| // ^hashfile.clear[] | const String::Body key, |
| add_native_method("clear", Method::CT_DYNAMIC, _clear, 0, 0); | const String& value, |
| // ^cache[key](seconds){code} | void* ainfo) { |
| add_native_method("cache", Method::CT_DYNAMIC, _cache, 3, 3); | Foreach_info& info=*static_cast<Foreach_info*>(ainfo); |
| // ^cancel[] | if(info.key_var_name){ |
| add_native_method("cancel", Method::CT_DYNAMIC, _cancel, 0, 0); | VString* vkey=new VString(key); |
| // ^lock{code} | info.r->put_element(*info.var_context, *info.key_var_name, vkey); |
| add_native_method("lock", Method::CT_DYNAMIC, _lock, 1, 1); | } |
| // ^pack[] | if(info.value_var_name){ |
| add_native_method("pack", Method::CT_DYNAMIC, _pack, 0, 0); | VString* vvalue=new VString(value); |
| */ | info.r->put_element(*info.var_context, *info.value_var_name, vvalue); |
| } | |
| Value& sv_processed=info.r->process(*info.body_code); | |
| TempSkip4Delimiter skip(*info.r); | |
| const String* s_processed=sv_processed.get_string(); | |
| 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? | |
| info.r->write(info.r->process(*info.delim_maybe_code)); | |
| else | |
| info.need_delim=true; | |
| } | |
| info.r->write(sv_processed); | |
| return skip.check_break(); | |
| } | } |
| static void _foreach(Request& r, MethodParams& params) { | |
| InCycle temp(r); | |
| // global variable | 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"); | |
| Methoded *hashfile_base_class; | 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 ? ¶ms[3] : 0, | |
| /*var_context*/r.get_method_frame()->caller(), | |
| false | |
| }; | |
| // creator | VHashfile& self=GET_SELF(r, VHashfile); |
| self.for_each(one_foreach_cycle, &info); | |
| } | |
| Methoded *MHashfile_create(Pool& pool) { | static bool one_cleanup_cycle(const String::Body, const String&, void*) { |
| return hashfile_base_class=new(pool) MHashfile(pool); | return false; |
| } | } |
| static void _cleanup(Request& r, MethodParams&) { | |
| VHashfile& self=GET_SELF(r, VHashfile); | |
| #endif | self.for_each(one_cleanup_cycle, 0); |
| } | |
| static void _release(Request& r, MethodParams&) { | |
| VHashfile& self=GET_SELF(r, VHashfile); | |
| self.close(); | |
| } | |
| // constructor | |
| MHashfile::MHashfile(): Methoded("hashfile") { | |
| // ^hashfile::open[filename] | |
| add_native_method("open", Method::CT_DYNAMIC, _open, 1, 1); | |
| // ^hashfile.hash[] | |
| add_native_method("hash", Method::CT_DYNAMIC, _hash, 0, 0); | |
| // ^hashfile.delete[key] | |
| add_native_method("delete", Method::CT_DYNAMIC, _delete, 0, 1); | |
| // ^hashfile.clear[] -- for backward compatibility. use .delete[] instead. | |
| 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] | |
| add_native_method("foreach", Method::CT_DYNAMIC, _foreach, 2+1, 2+1+1); | |
| } |