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