|
|
| version 1.15, 2002/02/19 15:05:27 | version 1.22, 2002/08/01 11:26:44 |
|---|---|
| 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, 2002 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="$Id$"; | |
| #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 PI 3.1415926535 |
| #define MATH_CLASS_NAME "math" | #define MAX_SALT 8 |
| // class | // class |
| Line 34 public: // Methoded | Line 40 public: // Methoded |
| // methods | // methods |
| static unsigned int randomizer=0; | static unsigned int randomizer=0; |
| static inline int _random(uint top) { | |
| return (int)(((double)((randomizer=rand())% RAND_MAX)) / RAND_MAX * top ); | |
| } | |
| static void _random(Request& r, const String& method_name, MethodParams *params) { | static void _random(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| Value& range=params->as_junction(0, "range must be expression"); | Value& 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(0, 0, | 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(*new(pool) VInt(pool, _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; } |
| Line 62 static void math1(Request& r, | Line 68 static void math1(Request& r, |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| Value& 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(*new(pool) VDouble(pool, result)); |
| r.write_no_lang(result); | |
| } | } |
| #define MATH1(name) \ | #define MATH1(name) \ |
| Line 94 static void math2(Request& r, | Line 99 static void math2(Request& r, |
| Value& a=params->as_junction(0, "parameter must be expression"); | Value& a=params->as_junction(0, "parameter must be expression"); |
| Value& 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(*new(pool) VDouble(pool, result)); |
| r.write_no_lang(result); | |
| } | } |
| #define MATH2(name) \ | #define MATH2(name) \ |
| Line 107 static void math2(Request& r, | Line 111 static void math2(Request& r, |
| } | } |
| 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, const String& method_name, MethodParams *params) { | |
| Pool& pool=r.pool(); | |
| const char *password=params->as_string(0, "password must be string").cstr(); | |
| const char *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=(char *)pool.malloc(sample_size); | |
| pa_MD5Encode((const unsigned char *)password, | |
| (const unsigned char *)normal_salt, sample_buf, sample_size); | |
| r.write_pass_lang(*new(pool) String(pool, sample_buf)); | |
| } else { | |
| #ifdef HAVE_CRYPT | |
| const char *sample_buf=crypt(password, normal_salt); | |
| if(!sample_buf // nothing generated | |
| || !sample_buf[0] // generated nothing | |
| || strncmp(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(*new(pool) String(pool, 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(Pool& apool) : Methoded(apool, "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 198 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 214 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(); |