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