|
|
| version 1.16, 2002/03/27 15:30:34 | version 1.24.2.6, 2003/02/06 11:56:31 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: @b math parser class. | Parser: @b math parser class. |
| Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) | Copyright(c) 2001-2003 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) |
| $Id$ | |
| */ | */ |
| static const char* IDENT_MATH_C="$Date$"; | |
| #include "pa_vmethod_frame.h" | |
| #include "pa_common.h" | #include "pa_common.h" |
| #include "pa_vint.h" | #include "pa_vint.h" |
| #include "pa_vmath.h" | #include "pa_vmath.h" |
| #include "pa_request.h" | #include "pa_request.h" |
| #include "pa_md5.h" | |
| #ifdef WIN32 | #ifdef WIN32 |
| // for threadID | |
| # include <windows.h> | # include <windows.h> |
| #endif | #endif |
| #ifdef HAVE_CRYPT_H | |
| #include <crypt.h> | |
| #endif | |
| // defines | // defines |
| #define PI 3.1415926535 | #define MAX_SALT 8 |
| #define MATH_CLASS_NAME "math" | |
| // class | // class |
| class MMath : public Methoded { | class MMath : public Methoded { |
| public: | public: |
| MMath(Pool& pool); | MMath(); |
| void configure_admin(Request& r); | void configure_admin(Request& r); |
| public: // Methoded | public: // Methoded |
| bool used_directly() { return false; } | bool used_directly() { return false; } |
| }; | }; |
| // global variables | |
| VStateless_classPtr math_base_class(new MMath); | |
| // methods | // methods |
| static unsigned int randomizer=0; | static unsigned int randomizer=0; |
| static void _random(Request& r, const String& method_name, MethodParams *params) { | static inline int _random(uint top) { |
| return (int)(((double)((randomizer=rand())% RAND_MAX)) / RAND_MAX * top ); | |
| } | |
| static void _random(Request& r, StringPtr method_name, MethodParams& params) { | |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| Value& range=params->as_junction(0, "range must be expression"); | ValuePtr range=params.as_junction(0, "range must be expression"); |
| double top=r.process(range).as_double(); | double top=r.process_to_value(range)->as_double(); |
| if(top<=1) | if(top<=1) |
| throw Exception("parser.runtime", | throw Exception("parser.runtime", |
| &method_name, | method_name, |
| "top must be above 1 (%g)", top); | "top must be above 1(%g)", top); |
| Value& result=*new(pool) VInt(pool, (int)( | r.write_no_lang(ValuePtr(new VInt(_random(uint(top))))); |
| ((double)((randomizer=rand())% RAND_MAX)) / RAND_MAX * uint(top) )); | |
| result.set_name(method_name); | |
| r.write_no_lang(result); | |
| } | } |
| typedef double (*math1_func_ptr)(double); | typedef double(*math1_func_ptr)(double); |
| static double frac(double param) { return param-trunc(param); } | static double frac(double param) { return param-trunc(param); } |
| static double degrees(double param) { return param /PI *180; } | static double degrees(double param) { return param /PI *180; } |
| static double radians(double param) { return param /180 *PI; } | static double radians(double param) { return param /180 *PI; } |
| static void math1(Request& r, | static void math1(Request& r, |
| const String& method_name, MethodParams *params, | StringPtr method_name, MethodParams& params, |
| math1_func_ptr func) { | math1_func_ptr func) { |
| Pool& pool=r.pool(); | ValuePtr param=params.as_junction(0, "parameter must be expression"); |
| Value& param=params->as_junction(0, "parameter must be expression"); | |
| Value& result=*new(pool) VDouble(pool, (*func)(r.process(param).as_double())); | double result=func(r.process_to_value(param)->as_double()); |
| result.set_name(method_name); | r.write_no_lang(ValuePtr(new VDouble(result))); |
| r.write_no_lang(result); | |
| } | } |
| #define MATH1(name) \ | #define MATH1(name) \ |
| static void _##name(Request& r, const String& method_name, MethodParams *params) {\ | static void _##name(Request& r, StringPtr method_name, MethodParams& params) {\ |
| math1(r, method_name, params, &name);\ | math1(r, method_name, params, &name);\ |
| } | } |
| #define MATH1P(name_parser, name_c) \ | #define MATH1P(name_parser, name_c) \ |
| static void _##name_parser(Request& r, const String& method_name, MethodParams *params) {\ | static void _##name_parser(Request& r, StringPtr method_name, MethodParams& params) {\ |
| math1(r, method_name, params, &name_c);\ | math1(r, method_name, params, &name_c);\ |
| } | } |
| MATH1(round); MATH1(floor); MATH1P(ceiling, ceil); | MATH1(round); MATH1(floor); MATH1P(ceiling, ceil); |
| Line 88 MATH1(sqrt); | Line 97 MATH1(sqrt); |
| typedef double (*math2_func_ptr)(double, double); | typedef double (*math2_func_ptr)(double, double); |
| static void math2(Request& r, | static void math2(Request& r, |
| const String& method_name, MethodParams *params, | StringPtr method_name, MethodParams& params, |
| math2_func_ptr func) { | math2_func_ptr func) { |
| Pool& pool=r.pool(); | ValuePtr a=params.as_junction(0, "parameter must be expression"); |
| Value& a=params->as_junction(0, "parameter must be expression"); | ValuePtr b=params.as_junction(1, "parameter must be expression"); |
| Value& b=params->as_junction(1, "parameter must be expression"); | |
| Value& result=*new(pool) VDouble(pool, (*func)( | double result=func( |
| r.process(a).as_double(), | r.process_to_value(a)->as_double(), |
| r.process(b).as_double())); | r.process_to_value(b)->as_double()); |
| result.set_name(method_name); | r.write_no_lang(ValuePtr(new VDouble(result))); |
| r.write_no_lang(result); | |
| } | } |
| #define MATH2(name) \ | #define MATH2(name) \ |
| static void _##name(Request& r, const String& method_name, MethodParams *params) {\ | static void _##name(Request& r, StringPtr method_name, MethodParams& params) {\ |
| math2(r, method_name, params, &name);\ | math2(r, method_name, params, &name);\ |
| } | } |
| MATH2(pow); | MATH2(pow); |
| inline bool is_salt_body_char(int c) { | |
| return isalnum(c) || c == '.' || c=='/'; | |
| } | |
| static size_t calc_prefix_size(const char* salt) { | |
| if(size_t salt_size=strlen(salt)) { | |
| if(!is_salt_body_char(salt[0])) { // $... {... | |
| const char* cur=salt+1; // skip | |
| while(is_salt_body_char(*cur++)) // ...$ ...} | |
| ; | |
| return cur-salt; | |
| } else | |
| return 0; | |
| } else | |
| return 0; | |
| } | |
| static void _crypt(Request& r, StringPtr method_name, MethodParams& params) { | |
| Pool& pool=r.pool(); | |
| CharPtr password=params.as_string(0, "password must be string")->cstr(); | |
| CharPtr maybe_bodyless_salt=params.as_string(1, "salt must be string")->cstr(); | |
| size_t prefix_size=calc_prefix_size(maybe_bodyless_salt); | |
| const char* normal_salt; | |
| char normalize_buf[MAX_STRING]; | |
| if(prefix_size==strlen(maybe_bodyless_salt)) { // bodyless? | |
| strncpy(normalize_buf, maybe_bodyless_salt, MAX_STRING-MAX_SALT-1); | |
| char *cur=normalize_buf+strlen(normalize_buf); | |
| // sould add up MAX_SALT random chars | |
| static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */ | |
| "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | |
| for(int i=0; i<MAX_SALT; i++) | |
| *cur++=itoa64[_random(64)]; | |
| *cur=0; | |
| normal_salt=normalize_buf; | |
| } else | |
| normal_salt=maybe_bodyless_salt; | |
| /* FreeBSD style MD5 string | |
| */ | |
| if(strncmp(normal_salt, PA_MD5PW_ID, PA_MD5PW_IDLEN) == 0) { | |
| const size_t sample_size=120; | |
| char *sample_buf=new(pool) char[sample_size]; | |
| pa_MD5Encode((const unsigned char *)password.get(), | |
| (const unsigned char *)normal_salt, sample_buf, sample_size); | |
| String sample(sample_buf); | |
| r.write_pass_lang(sample); | |
| } else { | |
| #ifdef HAVE_CRYPT | |
| const char* static_sample_buf=crypt(password, normal_salt); | |
| if(!static_sample_buf // nothing generated | |
| || !static_sample_buf[0] // generated nothing | |
| || strncmp(static_sample_buf, normal_salt, prefix_size)!=0) // salt prefix not preserved | |
| throw Exception("parser.runtime", | |
| method_name, | |
| "on this platform does not support '%.*s' salt prefix", prefix_size, normal_salt); | |
| r.write_pass_lang(StringPtr(new String(pool.copy(static_sample_buf)))); | |
| #else | |
| throw Exception("parser.runtime", | |
| method_name, | |
| "salt must start with '" PA_MD5PW_ID "'"); | |
| #endif | |
| } | |
| } | |
| // constructor | // constructor |
| MMath::MMath(Pool& apool) : Methoded(apool) { | MMath::MMath(): Methoded("math") { |
| set_name(*NEW String(pool(), MATH_CLASS_NAME)); | |
| // ^FUNC(expr) | // ^FUNC(expr) |
| #define ADD1(name) \ | #define ADD1(name) \ |
| add_native_method(#name, Method::CT_STATIC, _##name, 1, 1) | add_native_method(#name, Method::CT_STATIC, _##name, 1, 1) |
| Line 133 MMath::MMath(Pool& apool) : Methoded(apo | Line 202 MMath::MMath(Pool& apool) : Methoded(apo |
| // ^pow(x;y) | // ^pow(x;y) |
| ADD2(pow); | ADD2(pow); |
| // ^crypt[password;salt] | |
| ADD2(crypt); | |
| } | } |
| // in MSVC each thread has it's own pseudo-random sequence | // in MSVC each thread has it's own pseudo-random sequence |
| Line 147 void MMath::configure_admin(Request&) { | Line 218 void MMath::configure_admin(Request&) { |
| #else | #else |
| ^ getpid() | ^ getpid() |
| #endif | #endif |
| ^ (unsigned int)time(NULL) | ^(unsigned int)time(NULL) |
| ); | ); |
| if(!randomizer) | if(!randomizer) |
| randomizer=rand(); | randomizer=rand(); |
| } | } |
| // global variables | |
| Methoded *math_base_class; | |
| Hash *math_consts; | |
| // creator | |
| Methoded *MMath_create(Pool& pool) { | |
| math_consts=new(pool) Hash(pool); | |
| math_consts->put( | |
| *new(pool) String(pool, "PI"), | |
| new(pool) VDouble(pool, PI)); | |
| return math_base_class=new(pool) MMath(pool); | |
| } |