Annotation of parser3/src/classes/op.C, revision 1.9.2.2
1.1 paf 1: /** @file
1.9 paf 2: Parser: parser @b operators.
1.1 paf 3:
4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
5:
6: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
7:
1.9.2.2 ! paf 8: $Id: op.C,v 1.9.2.1 2001/04/27 15:19:23 paf Exp $
1.1 paf 9: */
10:
1.9.2.1 paf 11: #include "classes.h"
1.1 paf 12: #include "pa_config_includes.h"
13: #include "pa_common.h"
14: #include "pa_request.h"
15: #include "pa_vint.h"
16: #include "pa_sql_connection.h"
17:
1.9.2.1 paf 18: // defines
19:
20: #define OP_CLASS_NAME "OP"
21:
22: // class
23:
24: class MOP : public Methoded {
25: public:
26: MOP(Pool& pool);
27: bool used_directly() { return true; }
28: };
29:
30: // methods
31:
1.5 paf 32: static void _if(Request& r, const String&, MethodParams *params) {
33: Value& condition_code=params->get(0);
1.1 paf 34:
35: bool condition=r.process(condition_code,
36: 0/*no name*/,
37: false/*don't intercept string*/).as_bool();
1.6 paf 38: if(condition)
1.5 paf 39: r.write_pass_lang(r.process(params->get(1)));
1.6 paf 40: else if(params->size()==3)
1.5 paf 41: r.write_pass_lang(r.process(params->get(2)));
1.1 paf 42: }
43:
1.5 paf 44: static void _untaint(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 45: Pool& pool=r.pool();
46:
1.5 paf 47: const String& lang_name=r.process(params->get(0)).as_string();
1.1 paf 48: String::Untaint_lang lang=static_cast<String::Untaint_lang>(
49: untaint_lang_name2enum->get_int(lang_name));
50: if(!lang)
51: PTHROW(0, 0,
52: &lang_name,
53: "invalid untaint language");
54:
55: {
1.5 paf 56: Value& vbody=params->get_junction(1, "body must be code");
1.1 paf 57:
58: Temp_lang temp_lang(r, lang); // set temporarily specified ^untaint[language;
1.5 paf 59: r.write_pass_lang(r.process(vbody)); // process marking tainted with that lang
1.1 paf 60: }
61: }
62:
1.5 paf 63: static void _taint(Request& r, const String&, MethodParams *params) {
1.1 paf 64: Pool& pool=r.pool();
65:
66: String::Untaint_lang lang;
67: if(params->size()==1)
68: lang=String::UL_TAINTED; // mark as simply 'tainted'. useful in table:set
69: else {
1.3 paf 70: const String& lang_name=
1.5 paf 71: r.process(params->get(0)).as_string();
1.1 paf 72: lang=static_cast<String::Untaint_lang>(
73: untaint_lang_name2enum->get_int(lang_name));
74: if(!lang)
75: PTHROW(0, 0,
1.3 paf 76: &lang_name,
77: "invalid taint language");
1.1 paf 78: }
79:
80: {
1.5 paf 81: Value& vbody=params->get_no_junction(params->size()-1, "body must not be code");
1.1 paf 82:
83: String result(r.pool());
84: result.append(
85: vbody.as_string(), // process marking tainted with that lang
86: lang, true); // force result language to specified
87: r.write_pass_lang(result);
88: }
89: }
90:
1.5 paf 91: static void _process(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 92: // calculate pseudo file name of processed chars
93: // would be something like "/some/file(4) process"
94: char place[MAX_STRING];
95: #ifndef NO_STRING_ORIGIN
96: const Origin& origin=method_name.origin();
97: snprintf(place, MAX_STRING, "%s(%d) %s",
98: origin.file, 1+origin.line,
99: method_name.cstr());
100: #else
101: strncpy(place, MAX_STRING, method_name.cstr());
102: #endif
103:
104: VStateless_class& self_class=*r.self->get_class();
105: {
106: // temporary zero @main so to maybe-replace it in processed code
107: Temp_method temp_method_main(self_class, *main_method_name, 0);
108: // temporary zero @auto so it wouldn't be auto-called in Request::use_buf
109: Temp_method temp_method_auto(self_class, *auto_method_name, 0);
110:
111: // evaluate source to process
112: const String& source=
1.5 paf 113: r.process(params->get(0)).as_string();
1.1 paf 114:
115: // process source code, append processed methods to 'self' class
116: // maybe-define new @main
117: r.use_buf(source.cstr(), place, &self_class);
118:
119: // maybe-execute @main[]
120: if(const Method *method=self_class.get_method(*main_method_name)) {
121: // execute!
122: r.execute(*method->parser_code);
123: }
124: }
125: }
126:
1.5 paf 127: static void _rem(Request& r, const String&, MethodParams *params) {
128: params->get_junction(0, "body must be code");
1.1 paf 129: }
130:
1.5 paf 131: static void _while(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 132: Pool& pool=r.pool();
133:
1.5 paf 134: Value& vcondition=params->get_junction(0, "condition must be expression");
135: Value& body=params->get_junction(1, "body must be code");
1.1 paf 136:
137: // while...
138: int endless_loop_count=0;
139: while(true) {
140: if(++endless_loop_count>=1973) // endless loop?
141: PTHROW(0, 0,
142: &method_name,
143: "endless loop detected");
144:
145: bool condition=
146: r.process(
147: vcondition,
148: 0/*no name*/,
149: false/*don't intercept string*/).as_bool();
150: if(!condition) // ...condition is true
151: break;
152:
153: // write processed body
154: r.write_pass_lang(r.process(body));
155: }
156: }
157:
1.5 paf 158: static void _use(Request& r, const String& method_name, MethodParams *params) {
159: Value& vfile=params->get_no_junction(0, "file name must not be code");
1.1 paf 160: r.use_file(r.absolute(vfile.as_string()));
161: }
162:
1.4 paf 163: /// ^for[i;from-number;to-number-inclusive]{code}[delim]
1.5 paf 164: static void _for(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 165: Pool& pool=r.pool();
1.5 paf 166: const String& var_name=r.process(params->get(0)).as_string();
167: int from=(int)r.process(params->get(1)).as_double();
168: int to=(int)r.process(params->get(2)).as_double();
169: Value& body_code=params->get_junction(3, "body must be code");
170: Value *delim_code=params->size()==3+1+1?¶ms->get(3+1):0;
1.1 paf 171:
172: bool need_delim=false;
173: VInt *vint=new(pool) VInt(pool, 0);
174: int endless_loop_count=0;
175: for(int i=from; i<=to; i++) {
176: if(++endless_loop_count>=2001) // endless loop?
177: PTHROW(0, 0,
178: &method_name,
179: "endless loop detected");
180: vint->set_int(i);
1.4 paf 181: r.root->put_element(var_name, vint);
1.1 paf 182:
183: Value& processed_body=r.process(body_code);
184: if(delim_code) { // delimiter set?
185: const String *string=processed_body.get_string();
186: if(need_delim && string && string->size()) // need delim & iteration produced string?
187: r.write_pass_lang(r.process(*delim_code));
188: need_delim=true;
189: }
190: r.write_pass_lang(processed_body);
191: }
192: }
193:
1.5 paf 194: static void _eval(Request& r, const String&, MethodParams *params) {
195: Value& expr=params->get_junction(0, "need expression");
1.1 paf 196: // evaluate expresion
197: Value *result=r.process(expr,
198: 0/*no name*/,
199: true/*don't intercept string*/).as_expr_result();
200: if(params->size()==2) {
1.5 paf 201: Value& fmt=params->get_no_junction(1, "fmt must not be code");
1.1 paf 202:
203: Pool& pool=r.pool();
204: String& string=*new(pool) String(pool);
205: string.APPEND_CONST(format(pool, result->as_double(), fmt.as_string().cstr()));
206: result=new(pool) VString(string);
207: }
208: r.write_no_lang(*result);
209: }
210:
211:
212: typedef double (*math_one_double_op_func_ptr)(double);
213: static double round(double op) { return floor(op+0.5); }
214: static double sign(double op) { return op > 0 ? 1 : ( op < 0 ? -1 : 0 ); }
215:
216: static void double_one_op(
217: Request& r,
1.5 paf 218: const String& method_name, MethodParams *params,
1.1 paf 219: math_one_double_op_func_ptr func) {
220: Pool& pool=r.pool();
1.5 paf 221: Value& param=params->get_junction(0, "parameter must be expression");
1.1 paf 222:
223: Value& result=*new(pool) VDouble(pool, (*func)(r.process(param).as_double()));
224: r.write_no_lang(result);
225: }
226:
1.5 paf 227: static void _round(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 228: double_one_op(r, method_name, params, &round);
229: }
230:
1.5 paf 231: static void _floor(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 232: double_one_op(r, method_name, params, &floor);
233: }
234:
1.5 paf 235: static void _ceiling(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 236: double_one_op(r, method_name, params, &ceil);
237: }
238:
1.5 paf 239: static void _abs(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 240: double_one_op(r, method_name, params, &fabs);
241: }
242:
1.5 paf 243: static void _sign(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 244: double_one_op(r, method_name, params, &sign);
245: }
246:
247: /// ^connect[protocol://user:pass@host[:port]/database]{code with ^sql-s}
1.5 paf 248: static void _connect(Request& r, const String&, MethodParams *params) {
1.1 paf 249: Pool& pool=r.pool();
250:
1.5 paf 251: Value& url=params->get_no_junction(0, "url must not be code");
252: Value& body_code=params->get_junction(1, "body must be code");
1.1 paf 253:
254: // connect
255: SQL_Connection& connection=SQL_driver_manager->get_connection(
256: url.as_string(), r.protocol2library);
257:
258: Exception rethrow_me;
259: // remember/set current connection
260: SQL_Connection *saved_connection=r.connection;
261: r.connection=&connection;
262: // execute body
263: bool body_failed=false;
264: PTRY
265: r.write_assign_lang(r.process(body_code));
266: PCATCH(e) { // connect/process problem
267: rethrow_me=e; body_failed=true;
268: }
269: PEND_CATCH
270:
271: bool finalizer_failed=false;
272: PTRY
273: // FINALLY
274: if(body_failed)
275: connection.rollback();
276: else
277: connection.commit();
278: PCATCH(e) { // commit/rollback problem
279: rethrow_me=e; finalizer_failed=true;
280: }
281: PEND_CATCH
282:
283: // close connection [cache it]
284: connection.close();
285: // recall current connection from remembered
286: r.connection=saved_connection;
287:
288: if(body_failed || finalizer_failed) // were there an exception for us to rethrow?
289: PTHROW(rethrow_me.type(), rethrow_me.code(),
290: rethrow_me.problem_source(),
291: rethrow_me.comment());
292: }
293:
1.9.2.1 paf 294: // constructor
295:
1.9.2.2 ! paf 296: MOP::MOP(Pool& pool) : Methoded(pool) {
1.9.2.1 paf 297: set_name(NEW String(pool, OP_CLASS_NAME));
1.1 paf 298:
299: // ^if(condition){code-when-true}
300: // ^if(condition){code-when-true}{code-when-false}
1.9.2.1 paf 301: add_native_method("if", Method::CT_ANY, _if, 2, 3);
1.1 paf 302:
303: // ^untaint[as-is|uri|sql|js|html|html-typo]{code}
1.9.2.1 paf 304: add_native_method("untaint", Method::CT_ANY, _untaint, 2, 2);
1.1 paf 305:
306: // ^taint[as-is|uri|sql|js|html|html-typo]{code}
1.9.2.1 paf 307: add_native_method("taint", Method::CT_ANY, _taint, 1, 2);
1.1 paf 308:
309: // ^process[code]
1.9.2.1 paf 310: add_native_method("process", Method::CT_ANY, _process, 1, 1);
1.1 paf 311:
312: // ^rem{code}
1.9.2.1 paf 313: add_native_method("rem", Method::CT_ANY, _rem, 1, 1);
1.1 paf 314:
315: // ^while(condition){code}
1.9.2.1 paf 316: add_native_method("while", Method::CT_ANY, _while, 2, 2);
1.1 paf 317:
318: // ^use[file]
1.9.2.1 paf 319: add_native_method("use", Method::CT_ANY, _use, 1, 1);
1.1 paf 320:
321: // ^for[i;from-number;to-number-inclusive]{code}[delim]
1.9.2.1 paf 322: add_native_method("for", Method::CT_ANY, _for, 3+1, 3+1+1);
1.1 paf 323:
324: // ^eval(expr)
325: // ^eval(expr)[format]
1.9.2.1 paf 326: add_native_method("eval", Method::CT_ANY, _eval, 1, 2);
1.1 paf 327:
328:
329: // math functions
330:
331: // ^round(expr)
1.9.2.1 paf 332: add_native_method("round", Method::CT_ANY, _round, 1, 1);
1.1 paf 333:
334: // ^floor(expr)
1.9.2.1 paf 335: add_native_method("floor", Method::CT_ANY, _floor, 1, 1);
1.1 paf 336:
337: // ^ceiling(expr)
1.9.2.1 paf 338: add_native_method("ceiling", Method::CT_ANY, _ceiling, 1, 1);
1.1 paf 339:
340: // ^abs(expr)
1.9.2.1 paf 341: add_native_method("abs", Method::CT_ANY, _abs, 1, 1);
1.1 paf 342:
343: // ^sign(expr)
1.9.2.1 paf 344: add_native_method("sign", Method::CT_ANY, _sign, 1, 1);
1.1 paf 345:
346:
347: // connect
348:
349: // ^connect[protocol://user:pass@host[:port]/database]{code with ^sql-s}
1.9.2.1 paf 350: add_native_method("connect", Method::CT_ANY, _connect, 2, 2);
351:
352: }
353: // creator
1.1 paf 354:
1.9.2.1 paf 355: Methoded *MOP_create(Pool& pool) {
356: return new(pool) MOP(pool);
1.1 paf 357: }
E-mail: