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