Annotation of parser3/src/classes/string.C, revision 1.125.2.15.2.2
1.24 paf 1: /** @file
2: Parser: @b string parser class.
3:
1.125.2.1 paf 4: Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com)
1.97 paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.113 paf 6: */
1.24 paf 7:
1.125.2.15.2. (paf 8:): static const char* IDENT_STRING_C="$Date: 2003/03/18 15:14:14 $";
1.1 paf 9:
1.43 paf 10: #include "classes.h"
1.125.2.4 paf 11: #include "pa_vmethod_frame.h"
12:
1.1 paf 13: #include "pa_request.h"
14: #include "pa_vdouble.h"
15: #include "pa_vint.h"
1.17 paf 16: #include "pa_vtable.h"
1.25 paf 17: #include "pa_vbool.h"
1.27 paf 18: #include "pa_string.h"
1.53 parser 19: #include "pa_sql_connection.h"
1.71 parser 20: #include "pa_dictionary.h"
1.119 paf 21: #include "pa_vmethod_frame.h"
1.1 paf 22:
1.41 paf 23: // class
24:
1.125.2.9 paf 25: class MString: public Methoded {
1.41 paf 26: public:
1.125.2.7 paf 27: MString();
1.44 paf 28: public: // Methoded
1.53 parser 29: bool used_directly() { return true; }
1.41 paf 30: };
1.1 paf 31:
1.125.2.7 paf 32: // global variable
33:
1.125.2.12 paf 34: DECLARE_CLASS_VAR(string, new MString, 0);
1.125.2.7 paf 35:
1.125.2.8 paf 36: // defines for statics
37:
38: #define MATCH_VAR_NAME "match"
39:
40: // statics
41:
1.125.2.15.2. (paf 42:): static const String& match_var_name(new String(MATCH_VAR_NAME));
1.125.2.8 paf 43:
1.1 paf 44: // methods
45:
1.125.2.15.2. (paf 46:): static void _length(Request& r, const String& method_name, MethodParams* ) {
1.125.2.7 paf 47: double result=GET_SELF(r, VString).string()->size();
48: r.write_no_lang(ValuePtr(new VDouble(result)));
1.1 paf 49: }
50:
1.125.2.15.2. (paf 51:): static void _int(Request& r, const String& method_name, MethodParams* params) {
52:): const String& self_string=r.get_self()->get_string(&pool);
1.72 parser 53: int converted;
1.125.2.10 paf 54: ValuePtr default_code=params->count()>0?params->as_junction(0, "default must be int")
1.125.2.7 paf 55: :ValuePtr(0); // (default)
1.84 parser 56: try {
1.121 paf 57: if(!self_string || self_string->is_empty())
58: throw Exception("parser.runtime",
1.125.2.5 paf 59: method_name,
1.121 paf 60: "parameter is empty string, error converting");
61: converted=self_string->as_int();
1.84 parser 62: } catch(...) { // convert problem
63: if(!default_code) // we have a problem when no default
1.125.2.2 paf 64: rethrow;
1.84 parser 65: else
1.125.2.7 paf 66: converted=r.process_to_value(default_code)->as_int();
1.72 parser 67: }
1.125.2.7 paf 68: r.write_no_lang(ValuePtr(new VInt(converted)));
1.1 paf 69: }
70:
1.125.2.15.2. (paf 71:): static void _double(Request& r, const String& method_name, MethodParams* params) {
72:): const String& self_string=GET_SELF(r, VString).string();
1.72 parser 73: double converted;
1.125.2.10 paf 74: ValuePtr default_code=params->count()>0?params->as_junction(0, "default must be double")
1.125.2.7 paf 75: :ValuePtr(0); // (default)
1.84 parser 76: try {
1.121 paf 77: if(!self_string || self_string->is_empty())
78: throw Exception("parser.runtime",
1.125.2.5 paf 79: method_name,
1.121 paf 80: "parameter is empty string, error converting");
81: converted=self_string->as_double();
1.84 parser 82: } catch(...) { // convert problem
83: if(!default_code) // we have a problem when no default
1.125.2.2 paf 84: rethrow;
1.84 parser 85: else
1.125.2.7 paf 86: converted=r.process_to_value(default_code)->as_double();
1.72 parser 87: }
88:
1.125.2.7 paf 89: r.write_no_lang(ValuePtr(new VDouble(converted)));
1.1 paf 90: }
91:
1.125.2.15.2. (paf 92:): /*not static*/void _string_format(Request& r, const String& method_name, MethodParams* params) {
1.9 paf 93:
1.125.2.10 paf 94: ValuePtr fmt_maybe_code=(*params)[0];
1.95 paf 95: // for some time due to stupid {} in original design
1.125.2.15.2. (paf 96:): const String& fmt=r.process_to_string(fmt_maybe_code);
1.9 paf 97:
1.125.2.7 paf 98: const char *buf=format(pool, r.get_self()->as_double(), fmt->cstr());
1.63 parser 99:
1.125.2.7 paf 100: String result;
1.63 parser 101: result.APPEND_CLEAN(buf, 0,
1.125.2.5 paf 102: method_name->origin().file,
103: method_name->origin().line);
1.63 parser 104: r.write_no_lang(result);
1.9 paf 105: }
1.11 paf 106:
1.125.2.15.2. (paf 107:): static void _left(Request& r, const String& /*method_name*/, MethodParams* params) {
1.125.2.10 paf 108: size_t n=(size_t)params->as_int(0, "n must be int", r);
1.15 paf 109:
1.125.2.15.2. (paf 110:): const String& string=GET_SELF(r, VString).string();
1.125.2.7 paf 111: r.write_assign_lang(*string->mid(0, n));
1.15 paf 112: }
113:
1.125.2.15.2. (paf 114:): static void _right(Request& r, const String& /*method_name*/, MethodParams* params) {
1.125.2.10 paf 115: size_t n=(size_t)params->as_int(0, "n must be int", r);
1.15 paf 116:
1.125.2.15.2. (paf 117:): const String& string=GET_SELF(r, VString).string();
1.125.2.7 paf 118: r.write_assign_lang(*string->mid(string->size()-n, string->size()));
1.15 paf 119: }
120:
1.125.2.15.2. (paf 121:): static void _mid(Request& r, const String& /*method_name*/, MethodParams* params) {
122:): const String& string=GET_SELF(r, VString).string();
1.83 parser 123:
1.125.2.10 paf 124: size_t p=(size_t)max(0, params->as_int(0, "p must be int", r));
125: size_t n=params->count()>1?
126: (size_t)max(0, params->as_int(1, "n must be int", r)):string->size();
1.15 paf 127:
1.125.2.7 paf 128: r.write_assign_lang(*string->mid(p, p+n));
1.15 paf 129: }
130:
1.125.2.15.2. (paf 131:): static void _pos(Request& r, const String& method_name, MethodParams* params) {
1.125.2.10 paf 132: ValuePtr substr=params->as_no_junction(0, "substr must not be code");
1.16 paf 133:
1.125.2.15.2. (paf 134:): const String& string=GET_SELF(r, VString).string();
1.125.2.7 paf 135: r.write_assign_lang(ValuePtr(new VInt(string->pos(*substr->as_string(&pool)))));
1.16 paf 136: }
137:
1.125.2.15.2. (paf 138:): static void split_list(Request& r, const String& method_name,
1.125.2.10 paf 139: MethodParams* params, int paramIndex,
1.125.2.7 paf 140: String& string,
141: ArrayString& result) {
1.125.2.10 paf 142: ValuePtr delim_value=params->as_no_junction(paramIndex, "delimiter must not be code");
1.23 paf 143:
1.125.2.7 paf 144: string.split(result, 0, *delim_value->as_string(&pool));
1.19 paf 145: }
146:
1.118 paf 147: #define SPLIT_LEFT 0x0001
148: #define SPLIT_RIGHT 0x0010
149: #define SPLIT_HORIZONTAL 0x0100
150: #define SPLIT_VERTICAL 0x1000
151:
1.125.2.15.2. (paf 152:): static int split_options(const String& options) {
1.118 paf 153: struct Split_option {
1.125.2.1 paf 154: const char* keyL;
155: const char* keyU;
1.118 paf 156: int setBit;
157: int checkBit;
158: } split_option[]={
159: {"l", "L", SPLIT_LEFT, SPLIT_RIGHT}, // 0xVHRL
160: {"r", "R", SPLIT_RIGHT, SPLIT_LEFT},
161: {"h", "H", SPLIT_HORIZONTAL, SPLIT_VERTICAL},
162: {"v", "V", SPLIT_VERTICAL, SPLIT_HORIZONTAL},
163: {0}
164: };
165:
166: int result=0;
167: if(options) {
168: for(Split_option *o=split_option; o->keyL; o++)
169: if(options->pos(o->keyL)>=0
170: || (o->keyU && options->pos(o->keyU)>=0)) {
171: if(result & o->checkBit)
172: throw Exception("parser.runtime",
173: options,
174: "conflicting split options");
175: result |= o->setBit;
176: }
177: }
178:
179: return result;
180: }
181:
1.125.2.15.2. (paf 182:): static Table* split_vertical(Request& r, const String& string, ArrayString& pieces, bool right) {
1.61 parser 183:
1.125.2.7 paf 184: Table::columns_type columns(new ArrayString);
1.125.2.15.2. (paf 185:): *columns+=String* (new String("piece"));
1.19 paf 186:
1.125.2.15.2. (paf 187:): Table* table(new Table(string, columns, pieces.count()));
1.118 paf 188: if(right) { // right
1.125.2.7 paf 189: for(int i=pieces.count(); --i>=0; ) {
190: Table::element_type row(new ArrayString);
191: *row+=pieces[i];
192: *table+=row;
1.118 paf 193: }
194: } else { // left
1.125.2.15.2. (paf 195:): Array_iterator<String* > i(pieces);
1.118 paf 196: while(i.has_next()) {
1.125.2.7 paf 197: Table::element_type row(new ArrayString);
198: *row+=i.next();
199: *table+=row;
1.118 paf 200: }
1.61 parser 201: }
1.118 paf 202:
1.125.2.7 paf 203: return table;
1.19 paf 204: }
205:
1.125.2.15.2. (paf 206:): static Table* split_horizontal(Request& r, const String& string, ArrayString& pieces, bool right) {
1.118 paf 207:
1.125.2.15.2. (paf 208:): Table* table(new Table(string, Table::columns_type(0) /* nameless */));
1.125.2.7 paf 209: Table::element_type row(new ArrayString(pieces.count()));
1.118 paf 210: if(right) { // right
1.125.2.7 paf 211: for(int i=pieces.count(); --i>=0; ) {
212: *row+=pieces[i];
1.118 paf 213: }
214: } else { // left
1.125.2.15.2. (paf 215:): Array_iterator<String* > i(pieces);
1.118 paf 216: while(i.has_next()) {
1.125.2.7 paf 217: *row+=i.next();
1.118 paf 218: }
219: }
1.125.2.7 paf 220: *table+=row;
1.118 paf 221:
1.125.2.7 paf 222: return table;
1.118 paf 223: }
224:
1.125.2.15.2. (paf 225:): static void split_with_options(Request& r, const String& method_name, MethodParams* params,
1.118 paf 226: int bits) {
1.125.2.15.2. (paf 227:): const String& string=GET_SELF(r, VString).string();
1.19 paf 228:
1.125.2.7 paf 229: ArrayString pieces;
230: split_list(r, method_name, params, 0, *string, pieces);
1.19 paf 231:
1.118 paf 232: if(!bits) {
1.125.2.15.2. (paf 233:): const String& options(0);
1.125.2.10 paf 234: if(params->count()>1) {
235: options=params->as_string(1, "options must not be code");
1.118 paf 236: }
237: bits=split_options(options);
238: }
1.21 paf 239:
1.118 paf 240: bool right=(bits & SPLIT_RIGHT) != 0;
241: bool horizontal=(bits & SPLIT_HORIZONTAL) !=0;
1.125.2.15.2. (paf 242:): Table* table=horizontal?split_horizontal(r, string, pieces, right)
1.125.2.7 paf 243: :split_vertical(r, string, pieces, right);
1.17 paf 244:
1.125.2.7 paf 245: r.write_no_lang(ValuePtr(new VTable(table)));
1.118 paf 246: }
1.125.2.15.2. (paf 247:): static void _split(Request& r, const String& method_name, MethodParams* params) {
1.118 paf 248: split_with_options(r, method_name, params, 0 /* maybe-determine from param #2 */);
249: }
1.125.2.15.2. (paf 250:): static void _lsplit(Request& r, const String& method_name, MethodParams* params) {
1.118 paf 251: split_with_options(r, method_name, params, SPLIT_LEFT);
252: }
1.125.2.15.2. (paf 253:): static void _rsplit(Request& r, const String& method_name, MethodParams* params) {
1.118 paf 254: split_with_options(r, method_name, params, SPLIT_RIGHT);
1.17 paf 255: }
256:
1.125.2.15.2. (paf 257:): static void search_action(Table* table, Table::element_type row, int, int, int, int, void *) {
1.28 paf 258: if(row)
1.125.2.7 paf 259: *table+=row;
1.27 paf 260: }
261:
1.74 parser 262: #ifndef DOXYGEN
1.27 paf 263: struct Replace_action_info {
1.125.2.7 paf 264: Request *request;
1.125.2.15.2. (paf 265:): const String& origin;
266:): const String& src; String* dest;
267:): VTable* vtable;
1.125.2.7 paf 268: ValuePtr replacement_code;
1.27 paf 269: };
1.74 parser 270: #endif
1.105 paf 271: /// @todo they can do $global[$result] there, getting pointer to later-invalid local var, kill this
1.125.2.15.2. (paf 272:): static void replace_action(Table* table, ArrayString& row,
1.104 paf 273: int prestart, int prefinish,
274: int poststart, int postfinish,
275: void *info) {
1.27 paf 276: Replace_action_info& ai=*static_cast<Replace_action_info *>(info);
1.31 paf 277: if(row) { // begin&middle
1.104 paf 278: // piece from last match['prestart'] to beginning of this match['prefinish']
279: if(prestart!=prefinish)
280: *ai.dest << ai.src->mid(prestart, prefinish);//ai.dest->APPEND_CONST("-");
1.51 parser 281: // store found parts in one-record VTable
1.125.2.7 paf 282: if(table->count()) // middle
283: table->put(0, row);
1.32 paf 284: else // begin
1.125.2.7 paf 285: *table+=row;
1.30 paf 286: { // execute 'replacement_code' in 'table' context
1.105 paf 287: ai.vtable->set_table(table);
1.30 paf 288:
1.125.2.7 paf 289: *ai.dest << ai.request->process_to_string(ai.replacement_code);
1.29 paf 290: }
291: } else // end
1.104 paf 292: *ai.dest << ai.src->mid(poststart, postfinish);
1.27 paf 293: }
294:
1.50 parser 295: /// @todo use pcre:study somehow
1.125.2.15.2. (paf 296:): static void _match(Request& r, const String& method_name, MethodParams* params) {
1.125.2.10 paf 297: ValuePtr regexp=params->as_no_junction(0, "regexp must not be code");
1.38 paf 298:
1.125.2.15.2. (paf 299:): const String& options=
1.125.2.10 paf 300: params->count()>1?
1.125.2.15.2. (paf 301:): params->as_no_junction(1, "options must not be code")->as_string(&pool):0;
1.24 paf 302:
303: Temp_lang temp_lang(r, String::UL_PASS_APPENDED);
1.125.2.15.2. (paf 304:): const String& src=GET_SELF(r, VString).string();
1.125.2.14 paf 305: bool just_matched;
1.125.2.10 paf 306: if(params->count()<3) { // search
1.125.2.15.2. (paf 307:): Table* table=src->match(r.charsets.source(),
1.125.2.5 paf 308: method_name,
1.125.2.7 paf 309: *regexp->as_string(&pool), options,
1.64 parser 310: search_action, 0,
1.125.2.14 paf 311: just_matched);
1.125.2.7 paf 312: ValuePtr result;
1.125.2.14 paf 313: if(table)
314: result=ValuePtr(new VTable(table)); // table of pre/match/post+substrings
1.64 parser 315: else
1.125.2.14 paf 316: result=ValuePtr(new VBool(just_matched));
1.125.2.7 paf 317: r.write_assign_lang(result);
1.27 paf 318: } else { // replace
1.125.2.10 paf 319: ValuePtr replacement_code=params->as_junction(2, "replacement param must be code");
1.24 paf 320:
1.125.2.7 paf 321: String result;
1.125.2.15.2. (paf 322:): VTable* vtable(new VTable);
1.125.2.7 paf 323: Replace_action_info info;
324: info.request=&r;
325: info.origin=method_name;
326: info.src=src;
327: info.dest=&result;
328: info.vtable=vtable;
329: info.replacement_code=replacement_code;
1.105 paf 330: Temp_value_element temp_match_var(
1.125.2.7 paf 331: *replacement_code->get_junction()->method_frame,
332: match_var_name, vtable);
333: src->match(r.charsets.source(),
1.125.2.5 paf 334: method_name,
1.125.2.7 paf 335: *r.process_to_string(regexp), options,
1.125.2.14 paf 336: replace_action, &info,
337: just_matched);
1.102 paf 338: r.write_assign_lang(result);
1.27 paf 339: }
1.24 paf 340: }
341:
1.125.2.15.2. (paf 342:): static void change_case(Request& r, const String& method_name, MethodParams* params,
1.49 parser 343: String::Change_case_kind kind) {
1.125.2.15.2. (paf 344:): const String& src=GET_SELF(r, VString).string();
1.49 parser 345:
1.125.2.7 paf 346: r.write_assign_lang(*src->change_case(pool, r.charsets.source(), kind));
1.49 parser 347: }
1.125.2.15.2. (paf 348:): static void _upper(Request& r, const String& method_name, MethodParams* params) {
1.49 parser 349: change_case(r, method_name, params, String::CC_UPPER);
350: }
1.125.2.15.2. (paf 351:): static void _lower(Request& r, const String& method_name, MethodParams* params) {
1.49 parser 352: change_case(r, method_name, params, String::CC_LOWER);
353: }
354:
1.65 parser 355: #ifndef DOXYGEN
1.125.2.7 paf 356: class String_sql_event_handlers: public SQL_Driver_query_event_handlers {
1.125.2.15.2. (paf 357:): const String& statement_string; const char* statement_cstr;
1.125.2.7 paf 358: bool got_column;
1.65 parser 359: public:
1.125.2.7 paf 360: bool got_cell;
1.125.2.15.2. (paf 361:): const String& result;
1.125.2.7 paf 362: public:
1.125.2.15 paf 363: String_sql_event_handlers(
1.125.2.15.2. (paf 364:): const String& astatement_string, const char* astatement_cstr):
1.125.2.15 paf 365: statement_string(astatement_string), statement_cstr(astatement_cstr),
366: got_column(false),
367: got_cell(false),
1.125.2.7 paf 368: result(new String) {}
1.65 parser 369:
1.124 paf 370: bool add_column(SQL_Error& error, void *ptr, size_t size) {
371: if(got_column) {
372: error=SQL_Error("parser.runtime",
1.125.2.7 paf 373: //statement_string,
1.65 parser 374: "result must contain exactly one column");
1.124 paf 375: return true;
376: }
1.65 parser 377: got_column=true;
1.124 paf 378: return false;
1.65 parser 379: }
1.124 paf 380: bool before_rows(SQL_Error& /*error*/ ) { /* ignore */ return false; }
381: bool add_row(SQL_Error& /*error*/) { /* ignore */ return false; }
382: bool add_row_cell(SQL_Error& error, void *ptr, size_t size) {
383: if(got_cell) {
384: error=SQL_Error("parser.runtime",
1.125.2.7 paf 385: //statement_string,
1.65 parser 386: "result must not contain more then one row");
1.124 paf 387: return true;
388: }
1.65 parser 389:
1.124 paf 390: try {
391: got_cell=true;
1.125.2.1 paf 392: result->APPEND_TAINTED((const char* )ptr, size, statement_cstr, 0);
1.124 paf 393: return false;
394: } catch(...) {
395: error=SQL_Error("exception occured in String_sql_event_handlers::add_row_cell");
396: return true;
397: }
1.65 parser 398: }
399: };
400: #endif
1.125.2.15.2. (paf 401:): extern const String& sql_limit_name;
402:): extern const String& sql_offset_name;
403:): extern const String& sql_default_name;
404:): extern const String& sql_distinct_name;
405:): const String& sql_result_string(Request& r, const String& method_name, MethodParams* params,
1.125.2.7 paf 406: HashStringValue*& options, ValuePtr& default_code) {
1.53 parser 407:
1.125.2.10 paf 408: ValuePtr statement=params->as_junction(0, "statement must be code");
1.53 parser 409:
1.70 parser 410: ulong limit=0;
411: ulong offset=0;
1.125.2.7 paf 412: default_code=ValuePtr(0);
1.125.2.10 paf 413: if(params->count()>1) {
414: ValuePtr voptions=params->as_no_junction(1, "options must be hash, not code");
1.125.2.7 paf 415: if(!voptions->is_string())
416: if(options=voptions->get_hash(method_name)) {
417: if(ValuePtr vlimit=options->get(sql_limit_name))
418: limit=(ulong)r.process_to_value(vlimit)->as_double();
419: if(ValuePtr voffset=options->get(sql_offset_name))
420: offset=(ulong)r.process_to_value(voffset)->as_double();
421: if(default_code=options->get(sql_default_name)) {
422: if(JunctionPtr default_junction=default_code->get_junction())
1.119 paf 423: ;//default_junction->change_context(statement.get_junction());
1.110 paf 424: else
1.98 paf 425: throw Exception("parser.runtime",
1.125.2.5 paf 426: method_name,
1.81 parser 427: "default option must be code");
428: }
1.73 parser 429: } else
1.98 paf 430: throw Exception("parser.runtime",
1.125.2.5 paf 431: method_name,
1.73 parser 432: "options must be hash");
1.70 parser 433: } else
434: options=0;
435:
1.53 parser 436: Temp_lang temp_lang(r, String::UL_SQL);
1.125.2.15.2. (paf 437:): const String& statement_string=r.process_to_string(statement);
1.125.2.1 paf 438: const char* statement_cstr=
1.125.2.7 paf 439: statement_string->cstr(pool, String::UL_UNSPECIFIED, r.connection(method_name));
440: String_sql_event_handlers handlers(statement_string, statement_cstr);
441: r.connection(method_name)->query(
1.117 paf 442: statement_cstr, offset, limit,
443: handlers,
444: statement_string);
1.53 parser 445:
1.65 parser 446: if(!handlers.got_cell)
1.125.2.15.2. (paf 447:): return 0; // no lines, caller should return second param[default value]
1.62 parser 448:
1.65 parser 449: return handlers.result;
1.53 parser 450: }
451:
1.125.2.15.2. (paf 452:): static void _sql(Request& r, const String& method_name, MethodParams* params) {
1.53 parser 453:
1.125.2.7 paf 454: HashStringValue* options;
455: ValuePtr default_code;
1.125.2.15.2. (paf 456:): const String& string=sql_result_string(r, method_name, params, options, default_code);
1.62 parser 457: if(!string) {
1.81 parser 458: if(default_code) {
1.125.2.7 paf 459: string=r.process_to_string(default_code);
1.81 parser 460: if(!string)
1.125.2.15.2. (paf 461:): string=String* (new String);
1.68 parser 462: } else
1.98 paf 463: throw Exception("parser.runtime",
1.125.2.5 paf 464: method_name,
1.81 parser 465: "produced no result, but no default option specified");
1.62 parser 466: }
1.100 paf 467:
1.102 paf 468: r.write_assign_lang(*string);
1.53 parser 469: }
470:
1.125.2.15.2. (paf 471:): static void _replace(Request& r, const String& method_name, MethodParams* params) {
472:): const String& src=GET_SELF(r, VString).string();
1.71 parser 473:
1.125.2.10 paf 474: Table* table=params->as_no_junction(0, "parameter must not be code")->get_table();
1.71 parser 475: if(!table)
1.98 paf 476: throw Exception("parser.runtime",
1.125.2.5 paf 477: method_name,
1.71 parser 478: "parameter must be table");
479:
1.125.2.15.2. (paf 480:): Table* tp(table);
1.125.2.13 paf 481: Dictionary dict2(tp, 1/*am not sure why using the =default parameter causes compile errors in replace*/ );
1.125.2.7 paf 482: r.write_assign_lang(*src->replace(pool, dict2));
1.71 parser 483: }
1.79 parser 484:
1.125.2.15.2. (paf 485:): static void _save(Request& r, const String& method_name, MethodParams* params) {
486:): const String& file_name=params->as_string(params->count()-1,
1.87 paf 487: "file name must be string");
1.79 parser 488:
1.125.2.15.2. (paf 489:): const String& src=GET_SELF(r, VString).string();
1.79 parser 490:
1.87 paf 491: bool do_append=false;
1.125.2.10 paf 492: if(params->count()>1) {
1.125.2.15.2. (paf 493:): const String& mode=params->as_string(0, "mode must be string");
1.125.2.7 paf 494: if(*mode=="append")
1.87 paf 495: do_append=true;
496: else
1.98 paf 497: throw Exception("parser.runtime",
1.125.2.7 paf 498: mode,
1.87 paf 499: "unknown mode, must be 'append'");
500: }
501:
1.79 parser 502: // write
1.125.2.15.2. (paf 503:): const char* buf=src->cstr(String::UL_UNSPECIFIED, r.connection(0/*no error if none*/));
1.94 paf 504: file_write(r.absolute(file_name),
1.89 paf 505: buf, strlen(buf), true, do_append);
1.79 parser 506: }
507:
1.125.2.15.2. (paf 508:): static void _normalize(Request& r, const String& method_name, MethodParams* /*params*/) {
509:): const String& src=GET_SELF(r, VString).string();
1.125.2.7 paf 510:
511: r.write_assign_lang(*src->join_chains(r.pool()));
1.109 paf 512: }
513:
1.41 paf 514: // constructor
515:
1.125.2.7 paf 516: MString::MString(): Methoded("string") {
1.1 paf 517: // ^string.length[]
1.41 paf 518: add_native_method("length", Method::CT_DYNAMIC, _length, 0, 0);
1.6 paf 519:
1.1 paf 520: // ^string.int[]
1.72 parser 521: // ^string.int(default)
522: add_native_method("int", Method::CT_DYNAMIC, _int, 0, 1);
1.1 paf 523: // ^string.double[]
1.72 parser 524: // ^string.double(default)
525: add_native_method("double", Method::CT_DYNAMIC, _double, 0, 1);
1.9 paf 526:
1.24 paf 527: // ^string.format{format}
1.41 paf 528: add_native_method("format", Method::CT_DYNAMIC, _string_format, 1, 1);
1.14 paf 529:
1.15 paf 530: // ^string.left(n)
1.41 paf 531: add_native_method("left", Method::CT_DYNAMIC, _left, 1, 1);
1.15 paf 532: // ^string.right(n)
1.41 paf 533: add_native_method("right", Method::CT_DYNAMIC, _right, 1, 1);
1.15 paf 534: // ^string.mid(p;n)
1.82 parser 535: add_native_method("mid", Method::CT_DYNAMIC, _mid, 1, 2);
1.16 paf 536:
537: // ^string.pos[substr]
1.41 paf 538: add_native_method("pos", Method::CT_DYNAMIC, _pos, 1, 1);
1.17 paf 539:
1.118 paf 540: // ^string.split[delim]
541: // ^string.split[delim][options]
542: add_native_method("split", Method::CT_DYNAMIC, _split, 1, 2);
543: // old names for backward compatibility
544: // ^string.lsplit[delim]
545: add_native_method("lsplit", Method::CT_DYNAMIC, _lsplit, 1, 1);
546: // ^string.rsplit[delim]
547: add_native_method("rsplit", Method::CT_DYNAMIC, _rsplit, 1, 1);
548:
1.32 paf 549: // ^string.match[regexp][options]
550: // ^string.match[regexp][options]{replacement-code}
1.41 paf 551: add_native_method("match", Method::CT_DYNAMIC, _match, 1, 3);
1.49 parser 552:
553: // ^string.toupper[]
554: add_native_method("upper", Method::CT_DYNAMIC, _upper, 0, 0);
555: // ^string.tolower[]
556: add_native_method("lower", Method::CT_DYNAMIC, _lower, 0, 0);
1.53 parser 557:
1.70 parser 558: // ^sql[query]
559: // ^sql[query][$.limit(1) $.offset(2) $.default[n/a]]
1.67 parser 560: add_native_method("sql", Method::CT_STATIC, _sql, 1, 2);
1.71 parser 561:
562: // ^string.replace[table]
563: add_native_method("replace", Method::CT_DYNAMIC, _replace, 1, 1);
1.79 parser 564:
565: // ^string.save[file]
1.87 paf 566: add_native_method("save", Method::CT_DYNAMIC, _save, 1, 2);
1.109 paf 567:
1.112 paf 568: // ^string.normalize[]
569: add_native_method("normalize", Method::CT_DYNAMIC, _normalize, 0, 0);
1.2 paf 570: }
E-mail: