mruby/c VM Source Code release 3.4
Loading...
Searching...
No Matches
c_string.c
Go to the documentation of this file.
1
13
14/***** Feature test switches ************************************************/
15/***** System headers *******************************************************/
16//@cond
17#include "vm_config.h"
18#include <stdlib.h>
19#include <string.h>
20#include <limits.h>
21#include <assert.h>
22//@endcond
23
24/***** Local headers ********************************************************/
25#include "mrubyc.h"
26
27/***** Constat values *******************************************************/
28/***** Macros ***************************************************************/
29/***** Typedefs *************************************************************/
30/***** Function prototypes **************************************************/
31/***** Local variables ******************************************************/
32/***** Global variables *****************************************************/
33/***** Signal catching functions ********************************************/
34/***** Local functions ******************************************************/
35#if MRBC_USE_STRING
36//================================================================
42static int is_space( int ch )
43{
44 static const char ws[] = " \t\r\n\f\v"; // '\0' on tail
45
46 for( int i = 0; i < sizeof(ws); i++ ) {
47 if( ch == ws[i] ) return 1;
48 }
49 return 0;
50}
51
52
53/***** Global functions *****************************************************/
54//================================================================
62mrbc_value mrbc_string_new(struct VM *vm, const void *src, int len)
63{
64 mrbc_value value = {.tt = MRBC_TT_STRING};
65
66 /*
67 Allocate handle and string buffer.
68 */
69 mrbc_string *h = mrbc_alloc(vm, sizeof(mrbc_string));
70 if( !h ) return value; // ENOMEM
71
72 uint8_t *str = mrbc_alloc(vm, len+1);
73 if( !str ) { // ENOMEM
74 mrbc_raw_free( h );
75 return value;
76 }
77
78 MRBC_INIT_OBJECT_HEADER( h, "ST" );
79 h->size = len;
80 h->data = str;
81
82 /*
83 Copy a source string.
84 */
85 if( src == NULL ) {
86 str[0] = '\0';
87 } else {
88 memcpy( str, src, len );
89 str[len] = '\0';
90 }
91
92 value.string = h;
93 return value;
94}
95
96
97//================================================================
105mrbc_value mrbc_string_new_alloc(struct VM *vm, void *buf, int len)
106{
107 mrbc_value value = {.tt = MRBC_TT_STRING};
108
109 /*
110 Allocate handle
111 */
112 mrbc_string *h = mrbc_alloc(vm, sizeof(mrbc_string));
113 if( !h ) return value; // ENOMEM
114
115 MRBC_INIT_OBJECT_HEADER( h, "ST" );
116 h->size = len;
117 h->data = buf;
118
119 value.string = h;
120 return value;
121}
122
123
124//================================================================
130{
132 mrbc_raw_free(str->string);
133}
134
135
136
137//================================================================
141{
142 mrbc_raw_realloc(str->string->data, 1);
143 str->string->data[0] = '\0';
144 str->string->size = 0;
145}
146
147
148#if defined(MRBC_ALLOC_VMID)
149//================================================================
152void mrbc_string_clear_vm_id(mrbc_value *str)
153{
154 mrbc_set_vm_id( str->string, 0 );
155 mrbc_set_vm_id( str->string->data, 0 );
156}
157#endif
158
159
160//================================================================
168{
169 mrbc_string *h1 = s1->string;
170
171 mrbc_value value = mrbc_string_new(vm, NULL, h1->size);
172 if( value.string == NULL ) return value; // ENOMEM
173
174 memcpy( value.string->data, h1->data, h1->size + 1 );
175
176 return value;
177}
178
179
180//================================================================
188mrbc_value mrbc_string_add(struct VM *vm, const mrbc_value *s1, const mrbc_value *s2)
189{
190 mrbc_string *h1 = s1->string;
191 mrbc_string *h2 = s2->string;
192
193 mrbc_value value = mrbc_string_new(vm, NULL, h1->size + h2->size);
194 if( value.string == NULL ) return value; // ENOMEM
195
196 memcpy( value.string->data, h1->data, h1->size );
197 memcpy( value.string->data + h1->size, h2->data, h2->size + 1 );
198
199 return value;
200}
201
202
203//================================================================
211{
212 int len1 = s1->string->size;
213 int len2 = (mrbc_type(*s2) == MRBC_TT_STRING) ? s2->string->size : 1;
214
215 uint8_t *str = mrbc_raw_realloc(s1->string->data, len1+len2+1);
216 if( !str ) return E_NOMEMORY_ERROR;
217
218 if( mrbc_type(*s2) == MRBC_TT_STRING ) {
219 memcpy(str + len1, s2->string->data, len2 + 1);
220 } else if( mrbc_type(*s2) == MRBC_TT_INTEGER ) {
221 str[len1] = s2->i;
222 str[len1+1] = '\0';
223 }
224
225 s1->string->size = len1 + len2;
226 s1->string->data = str;
227
228 return 0;
229}
230
231
232//================================================================
240int mrbc_string_append_cbuf(mrbc_value *s1, const void *s2, int len2)
241{
242 int len1 = s1->string->size;
243
244 uint8_t *str = mrbc_raw_realloc(s1->string->data, len1+len2+1);
245 if( !str ) return E_NOMEMORY_ERROR;
246
247 if( s2 ) {
248 memcpy(str + len1, s2, len2);
249 str[len1 + len2] = 0;
250 } else {
251 memset(str + len1, 0, len2 + 1);
252 }
253
254 s1->string->size = len1 + len2;
255 s1->string->data = str;
256
257 return 0;
258}
259
260
261//================================================================
269int mrbc_string_index(const mrbc_value *src, const mrbc_value *pattern, int offset)
270{
271 char *p1 = mrbc_string_cstr(src) + offset;
272 char *p2 = mrbc_string_cstr(pattern);
273 int try_cnt = mrbc_string_size(src) - mrbc_string_size(pattern) - offset;
274
275 while( try_cnt >= 0 ) {
276 if( memcmp( p1, p2, mrbc_string_size(pattern) ) == 0 ) {
277 return p1 - mrbc_string_cstr(src); // matched.
278 }
279 try_cnt--;
280 p1++;
281 }
282
283 return -1;
284}
285
286
287//================================================================
294int mrbc_string_strip(mrbc_value *src, int mode)
295{
296 char *p1 = mrbc_string_cstr(src);
297 char *p2 = p1 + mrbc_string_size(src) - 1;
298
299 // left-side
300 if( mode & 0x01 ) {
301 while( p1 <= p2 ) {
302 if( *p1 == '\0' ) break;
303 if( !is_space(*p1) ) break;
304 p1++;
305 }
306 }
307 // right-side
308 if( mode & 0x02 ) {
309 while( p1 <= p2 ) {
310 if( !is_space(*p2) ) break;
311 p2--;
312 }
313 }
314
315 int new_size = p2 - p1 + 1;
316 if( mrbc_string_size(src) == new_size ) return 0;
317
318 char *buf = mrbc_string_cstr(src);
319 if( p1 != buf ) memmove( buf, p1, new_size );
320 buf[new_size] = '\0';
321 mrbc_raw_realloc(buf, new_size+1); // shrink suitable size.
322 src->string->size = new_size;
323
324 return 1;
325}
326
327
328//================================================================
335{
336 char *p1 = mrbc_string_cstr(src);
337 char *p2 = p1 + mrbc_string_size(src) - 1;
338
339 if( *p2 == '\n' ) {
340 p2--;
341 }
342 if( *p2 == '\r' ) {
343 p2--;
344 }
345
346 int new_size = p2 - p1 + 1;
347 if( mrbc_string_size(src) == new_size ) return 0;
348
349 char *buf = mrbc_string_cstr(src);
350 buf[new_size] = '\0';
351 src->string->size = new_size;
352
353 return 1;
354}
355
356
357//================================================================
364{
365 int len = str->string->size;
366 int count = 0;
367 uint8_t *data = str->string->data;
368 while (len != 0) {
369 len--;
370 if ('a' <= data[len] && data[len] <= 'z') {
371 data[len] = data[len] - ('a' - 'A');
372 count++;
373 }
374 }
375 return count;
376}
377
378
379//================================================================
386{
387 int len = str->string->size;
388 int count = 0;
389 uint8_t *data = str->string->data;
390 while (len != 0) {
391 len--;
392 if ('A' <= data[len] && data[len] <= 'Z') {
393 data[len] = data[len] + ('a' - 'A');
394 count++;
395 }
396 }
397 return count;
398}
399
400
401//================================================================
404static void c_string_new(struct VM *vm, mrbc_value v[], int argc)
405{
406 if (argc == 1 && mrbc_type(v[1]) != MRBC_TT_STRING) {
407 mrbc_raisef( vm, MRBC_CLASS(TypeError), "no implicit conversion into %s", "String");
408 return;
409 }
410 if (argc > 1) {
411 mrbc_raise( vm, MRBC_CLASS(ArgumentError), "wrong number of arguments");
412 return;
413 }
414
415 mrbc_value value;
416 if (argc == 0) {
417 value = mrbc_string_new(vm, NULL, 0);
418 } else {
419 value = mrbc_string_dup(vm, &v[1]);
420 }
421 SET_RETURN(value);
422}
423
424
425//================================================================
428static void c_string_add(struct VM *vm, mrbc_value v[], int argc)
429{
430 if( mrbc_type(v[1]) != MRBC_TT_STRING ) {
431 mrbc_raise( vm, MRBC_CLASS(ArgumentError), 0 );
432 return;
433 }
434
435 mrbc_value value = mrbc_string_add(vm, &v[0], &v[1]);
436 SET_RETURN(value);
437}
438
439
440
441//================================================================
444static void c_string_mul(struct VM *vm, mrbc_value v[], int argc)
445{
446 if( mrbc_type(v[1]) != MRBC_TT_INTEGER ) {
447 mrbc_raisef( vm, MRBC_CLASS(TypeError), "no implicit conversion into %s", "String");
448 return;
449 }
450
451 if( v[1].i < 0 ) {
452 mrbc_raise( vm, MRBC_CLASS(ArgumentError), "negative argument");
453 return;
454 }
455
456 mrbc_value value = mrbc_string_new(vm, NULL,
457 mrbc_string_size(&v[0]) * mrbc_integer(v[1]));
458 if( value.string == NULL ) return; // ENOMEM
459
460 uint8_t *p = value.string->data;
461 for( int i = 0; i < v[1].i; i++ ) {
462 memcpy( p, mrbc_string_cstr(&v[0]), mrbc_string_size(&v[0]) );
463 p += mrbc_string_size(&v[0]);
464 }
465 *p = 0;
466
467 SET_RETURN(value);
468}
469
470
471
472//================================================================
475static void c_string_size(struct VM *vm, mrbc_value v[], int argc)
476{
477 mrbc_int_t size = mrbc_string_size(&v[0]);
478
479 SET_INT_RETURN( size );
480}
481
482
483
484//================================================================
487static void c_string_to_i(struct VM *vm, mrbc_value v[], int argc)
488{
489 int base = 10;
490 if( argc ) {
491 base = v[1].i;
492 if( base < 2 || base > 36 ) {
493 mrbc_raisef(vm, MRBC_CLASS(ArgumentError), "invalid radix %d", base);
494 return;
495 }
496 }
497
498 mrbc_int_t i = mrbc_atoi( mrbc_string_cstr(v), base );
499
500 SET_INT_RETURN( i );
501}
502
503
504#if MRBC_USE_FLOAT
505//================================================================
508static void c_string_to_f(struct VM *vm, mrbc_value v[], int argc)
509{
510 mrbc_float_t d = atof(mrbc_string_cstr(v));
511
512 SET_FLOAT_RETURN( d );
513}
514#endif
515
516
517//================================================================
520static void c_string_to_s(struct VM *vm, mrbc_value v[], int argc)
521{
522 if( v[0].tt == MRBC_TT_CLASS ) {
523 v[0] = mrbc_string_new_cstr(vm, mrbc_symid_to_str( v[0].cls->sym_id ));
524 return;
525 }
526}
527
528
529//================================================================
532static void c_string_append(struct VM *vm, mrbc_value v[], int argc)
533{
534 if( !mrbc_string_append( &v[0], &v[1] ) ) {
535 // raise ? ENOMEM
536 }
537}
538
539
540//================================================================
543static void c_string_slice(struct VM *vm, mrbc_value v[], int argc)
544{
545 int target_len = mrbc_string_size(v);
546 int pos, len;
547
548 // in case of slice(nth) -> String | nil
549 if( argc == 1 && v[1].tt == MRBC_TT_INTEGER ) {
550 pos = mrbc_integer(v[1]);
551 if( pos < 0 ) pos += target_len;
552 if( pos >= target_len ) goto RETURN_NIL;
553 len = 1;
554 }
555
556 // in case of slice(nth, len) -> String | nil
557 else if( argc == 2 && v[1].tt == MRBC_TT_INTEGER &&
558 v[2].tt == MRBC_TT_INTEGER ) {
559 pos = mrbc_integer(v[1]);
560 if( pos < 0 ) pos += target_len;
561 len = mrbc_integer(v[2]);
562 }
563
564 // in case of slice(Range) -> String | nil
565 else if( argc == 1 && v[1].tt == MRBC_TT_RANGE ) {
566 mrbc_value v1 = mrbc_range_first(&v[1]);
567 mrbc_value v2 = mrbc_range_last(&v[1]);
568 if( v1.tt != MRBC_TT_INTEGER || v2.tt != MRBC_TT_INTEGER ) {
569 mrbc_raise( vm, MRBC_CLASS(TypeError), 0 );
570 return;
571 }
572
573 pos = mrbc_integer(v1);
574 if( pos < 0 ) pos += target_len;
575 int pos2 = mrbc_integer(v2);
576 if( pos2 < 0 ) pos2 += target_len;
577 len = pos2 - pos;
578 if( !mrbc_range_exclude_end(&v[1]) ) len++;
579 }
580
581 // other case
582 else {
583 mrbc_raise( vm, MRBC_CLASS(ArgumentError), 0 );
584 return;
585 }
586
587 if( pos < 0 || pos > target_len ) goto RETURN_NIL;
588 if( len > target_len - pos ) len = target_len - pos;
589 if( v[1].tt == MRBC_TT_RANGE && len < 0 ) len = 0;
590 if( len < 0 ) goto RETURN_NIL;
591
592 mrbc_value ret = mrbc_string_new(vm, mrbc_string_cstr(v) + pos, len);
593 if( !ret.string ) goto RETURN_NIL; // ENOMEM
594
595 SET_RETURN(ret);
596 return; // normal return
597
598 RETURN_NIL:
600}
601
602
603//================================================================
606static void c_string_insert(struct VM *vm, mrbc_value v[], int argc)
607{
608 int pos, len;
609 mrbc_value *val;
610
611 // in case of self[pos] = val
612 if( argc == 2 && v[1].tt == MRBC_TT_INTEGER &&
613 v[2].tt == MRBC_TT_STRING ) {
614 pos = mrbc_integer(v[1]);
615 len = 1;
616 val = &v[2];
617 }
618
619 // in case of self[pos, len] = val
620 else if( argc == 3 && v[1].tt == MRBC_TT_INTEGER &&
621 v[2].tt == MRBC_TT_INTEGER &&
622 v[3].tt == MRBC_TT_STRING ) {
623 pos = mrbc_integer(v[1]);
624 len = mrbc_integer(v[2]);
625 val = &v[3];
626 }
627
628 // in case of self[Range] = val
629 else if( argc == 2 && v[1].tt == MRBC_TT_RANGE &&
630 v[2].tt == MRBC_TT_STRING ) {
631 mrbc_value v1 = mrbc_range_first(&v[1]);
632 mrbc_value v2 = mrbc_range_last(&v[1]);
633 if( v1.tt != MRBC_TT_INTEGER || v2.tt != MRBC_TT_INTEGER ) {
634 mrbc_raise( vm, MRBC_CLASS(TypeError), 0 );
635 return;
636 }
637
638 pos = mrbc_integer(v1);
639 if( pos < 0 ) pos += mrbc_string_size(v);
640 if( pos < 0 || pos > mrbc_string_size(v) ) {
641 mrbc_raise( vm, MRBC_CLASS(RangeError), 0 );
642 return;
643 }
644
645 int pos2 = mrbc_integer(v2);
646 if( pos2 < 0 ) pos2 += mrbc_string_size(v);
647 len = pos2 - pos;
648 if( !mrbc_range_exclude_end(&v[1]) ) len++;
649 if( len < 0 ) len = 0;
650 val = &v[2];
651 }
652
653 // other cases
654 else {
655 mrbc_raise( vm, MRBC_CLASS(TypeError), "Not supported" );
656 return;
657 }
658
659 int len1 = mrbc_string_size(v);
660 int len2 = mrbc_string_size(val);
661 if( pos < 0 ) pos = len1 + pos; // adjust to positive number.
662 if( len > len1 - pos ) len = len1 - pos;
663 if( pos < 0 || pos > len1 || len < 0) {
664 mrbc_raisef( vm, MRBC_CLASS(IndexError), "index %d out of string", pos );
665 return;
666 }
667
668 int len3 = len1 + len2 - len; // final length.
669 uint8_t *str = v->string->data;
670 if( len1 < len3 ) {
671 str = mrbc_realloc(vm, str, len3+1); // expand
672 if( !str ) return;
673 }
674
675 memmove( str + pos + len2, str + pos + len, len1 - pos - len + 1 );
676 memcpy( str + pos, mrbc_string_cstr(val), len2 );
677
678 if( len1 > len3 ) {
679 str = mrbc_realloc(vm, str, len3+1); // shrink
680 }
681
682 v->string->size = len1 + len2 - len;
683 v->string->data = str;
684
685 // return val
686 mrbc_decref(&v[0]);
687 v[0] = *val;
688 val->tt = MRBC_TT_EMPTY;
689}
690
691
692//================================================================
695static void c_string_chomp(struct VM *vm, mrbc_value v[], int argc)
696{
697 mrbc_value ret = mrbc_string_dup(vm, &v[0]);
698
699 mrbc_string_chomp(&ret);
700
701 SET_RETURN(ret);
702}
703
704
705//================================================================
708static void c_string_clear(struct VM *vm, mrbc_value v[], int argc)
709{
710 mrbc_string_clear(&v[0]);
711}
712
713
714//================================================================
717static void c_string_chomp_self(struct VM *vm, mrbc_value v[], int argc)
718{
719 if( mrbc_string_chomp(&v[0]) == 0 ) {
721 }
722}
723
724
725//================================================================
728static void c_string_dup(struct VM *vm, mrbc_value v[], int argc)
729{
730 mrbc_value ret = mrbc_string_dup(vm, &v[0]);
731
732 SET_RETURN(ret);
733}
734
735
736//================================================================
739static void c_string_empty(struct VM *vm, mrbc_value v[], int argc)
740{
742}
743
744
745//================================================================
748static void c_string_getbyte(struct VM *vm, mrbc_value v[], int argc)
749{
750 int len = mrbc_string_size(&v[0]);
751 mrbc_int_t idx = mrbc_integer(v[1]);
752
753 if( idx >= 0 ) {
754 if( idx >= len ) idx = -1;
755 } else {
756 idx += len;
757 }
758 if( idx >= 0 ) {
759 SET_INT_RETURN( ((uint8_t *)mrbc_string_cstr(&v[0]))[idx] );
760 } else {
762 }
763}
764
765
766//================================================================
769static void c_string_setbyte(struct VM *vm, mrbc_value v[], int argc)
770{
771 if( argc != 2 ) {
772 mrbc_raise(vm, MRBC_CLASS(ArgumentError), "wrong number of arguments");
773 return;
774 }
775
776 int len = mrbc_string_size(&v[0]);
777 mrbc_int_t idx = mrbc_integer(v[1]);
778 mrbc_int_t dat = mrbc_integer(v[2]);
779
780 if( idx < 0 ) {
781 idx += len;
782 }
783 if( idx < 0 || idx >= len ) {
784 mrbc_raisef( vm, MRBC_CLASS(IndexError), "index %d out of string", idx );
785 return;
786 }
787
788 mrbc_string_cstr(&v[0])[idx] = dat;
789
790 SET_INT_RETURN( dat );
791}
792
793
794//================================================================
797static void c_string_index(struct VM *vm, mrbc_value v[], int argc)
798{
799 int index;
800 int offset;
801
802 if( argc == 1 ) {
803 offset = 0;
804
805 } else if( argc == 2 && mrbc_type(v[2]) == MRBC_TT_INTEGER ) {
806 offset = v[2].i;
807 if( offset < 0 ) offset += mrbc_string_size(&v[0]);
808 if( offset < 0 ) goto NIL_RETURN;
809
810 } else {
811 mrbc_raise( vm, MRBC_CLASS(ArgumentError), 0 );
812 return;
813 }
814
815 index = mrbc_string_index(&v[0], &v[1], offset);
816 if( index < 0 ) goto NIL_RETURN;
817
818 SET_INT_RETURN(index);
819 return;
820
821 NIL_RETURN:
823}
824
825
826//================================================================
829static void c_string_inspect(struct VM *vm, mrbc_value v[], int argc)
830{
831 char buf[10] = "\\x";
832 mrbc_value ret = mrbc_string_new_cstr(vm, "\"");
833 const unsigned char *s = (const unsigned char *)mrbc_string_cstr(v);
834
835 for( int i = 0; i < mrbc_string_size(v); i++ ) {
836 if( s[i] < ' ' || 0x7f <= s[i] ) { // tiny isprint()
837 buf[2] = "0123456789ABCDEF"[s[i] >> 4];
838 buf[3] = "0123456789ABCDEF"[s[i] & 0x0f];
839 mrbc_string_append_cstr(&ret, buf);
840 } else {
841 buf[3] = s[i];
842 mrbc_string_append_cstr(&ret, buf+3);
843 }
844 }
845 mrbc_string_append_cstr(&ret, "\"");
846
847 SET_RETURN( ret );
848}
849
850
851//================================================================
854static void c_string_ord(struct VM *vm, mrbc_value v[], int argc)
855{
856 if( mrbc_string_size(v) == 0 ) {
857 mrbc_raise(vm, MRBC_CLASS(ArgumentError), "empty string");
858 return;
859 }
860
861 int i = ((uint8_t *)mrbc_string_cstr(v))[0];
862
863 SET_INT_RETURN( i );
864}
865
866
867//================================================================
870static void c_string_slice_self(struct VM *vm, mrbc_value v[], int argc)
871{
872 int target_len = mrbc_string_size(v);
873 int pos = mrbc_integer(v[1]);
874 int len;
875
876 // in case of slice!(nth) -> String | nil
877 if( argc == 1 && mrbc_type(v[1]) == MRBC_TT_INTEGER ) {
878 len = 1;
879
880 // in case of slice!(nth, len) -> String | nil
881 } else if( argc == 2 && mrbc_type(v[1]) == MRBC_TT_INTEGER &&
882 mrbc_type(v[2]) == MRBC_TT_INTEGER ) {
883 len = mrbc_integer(v[2]);
884
885 // other case
886 } else {
887 mrbc_raise( vm, MRBC_CLASS(ArgumentError), 0 );
888 return;
889 }
890
891 if( pos < 0 ) pos += target_len;
892 if( pos < 0 ) goto RETURN_NIL;
893 if( len > (target_len - pos) ) len = target_len - pos;
894 if( len < 0 ) goto RETURN_NIL;
895 if( argc == 1 && len <= 0 ) goto RETURN_NIL;
896
897 mrbc_value ret = mrbc_string_new(vm, mrbc_string_cstr(v) + pos, len);
898 if( !ret.string ) goto RETURN_NIL; // ENOMEM
899
900 if( len > 0 ) {
901 memmove( mrbc_string_cstr(v) + pos, mrbc_string_cstr(v) + pos + len,
902 mrbc_string_size(v) - pos - len + 1 );
903 v->string->size = mrbc_string_size(v) - len;
905 }
906
907 SET_RETURN(ret);
908 return; // normal return
909
910 RETURN_NIL:
912}
913
914
915//================================================================
918static void c_string_split(struct VM *vm, mrbc_value v[], int argc)
919{
920 mrbc_value ret = mrbc_array_new(vm, 0);
921 if( mrbc_string_size(&v[0]) == 0 ) goto DONE;
922
923 // check limit parameter.
924 int limit = 0;
925 if( argc >= 2 ) {
926 if( mrbc_type(v[2]) != MRBC_TT_INTEGER ) {
927 mrbc_raise( vm, MRBC_CLASS(ArgumentError), 0 );
928 return;
929 }
930 limit = v[2].i;
931 if( limit == 1 ) {
932 mrbc_array_push( &ret, &v[0] );
933 mrbc_incref( &v[0] );
934 goto DONE;
935 }
936 }
937
938 // check separator parameter.
939 mrbc_value sep = (argc == 0) ? mrbc_string_new_cstr(vm, " ") : v[1];
940 switch( mrbc_type(sep) ) {
941 case MRBC_TT_NIL:
942 sep = mrbc_string_new_cstr(vm, " ");
943 break;
944
945 case MRBC_TT_STRING:
946 break;
947
948 default:
949 mrbc_raise( vm, MRBC_CLASS(TypeError), 0 );
950 return;
951 }
952
953 int flag_strip = (mrbc_string_cstr(&sep)[0] == ' ') &&
954 (mrbc_string_size(&sep) == 1);
955 int offset = 0;
956 int sep_len = mrbc_string_size(&sep);
957 if( sep_len == 0 ) sep_len++;
958
959 while( 1 ) {
960 int pos, len = 0;
961
962 if( flag_strip ) {
963 for( ; offset < mrbc_string_size(&v[0]); offset++ ) {
964 if( !is_space( mrbc_string_cstr(&v[0])[offset] )) break;
965 }
966 if( offset > mrbc_string_size(&v[0])) break;
967 }
968
969 // check limit
970 if( limit > 0 && mrbc_array_size(&ret)+1 >= limit ) {
971 pos = -1;
972 goto SPLIT_ITEM;
973 }
974
975 // split by space character.
976 if( flag_strip ) {
977 pos = offset;
978 for( ; pos < mrbc_string_size(&v[0]); pos++ ) {
979 if( is_space( mrbc_string_cstr(&v[0])[pos] )) break;
980 }
981 len = pos - offset;
982 goto SPLIT_ITEM;
983 }
984
985 // split by each character.
986 if( mrbc_string_size(&sep) == 0 ) {
987 pos = (offset < mrbc_string_size(&v[0])-1) ? offset : -1;
988 len = 1;
989 goto SPLIT_ITEM;
990 }
991
992 // split by specified character.
993 pos = mrbc_string_index( &v[0], &sep, offset );
994 len = pos - offset;
995
996
997 SPLIT_ITEM:
998 if( pos < 0 ) len = mrbc_string_size(&v[0]) - offset;
999
1000 mrbc_value v1 = mrbc_string_new(vm, mrbc_string_cstr(&v[0]) + offset, len);
1001 mrbc_array_push( &ret, &v1 );
1002
1003 if( pos < 0 ) break;
1004 offset = pos + sep_len;
1005 }
1006
1007 // remove trailing empty item
1008 if( limit == 0 ) {
1009 while( 1 ) {
1010 int idx = mrbc_array_size(&ret) - 1;
1011 if( idx < 0 ) break;
1012
1013 mrbc_value v1 = mrbc_array_get( &ret, idx );
1014 if( mrbc_string_size(&v1) != 0 ) break;
1015
1016 mrbc_array_remove(&ret, idx);
1017 mrbc_string_delete( &v1 );
1018 }
1019 }
1020
1021 if( argc == 0 || mrbc_type(v[1]) == MRBC_TT_NIL ) {
1022 mrbc_string_delete(&sep);
1023 }
1024
1025 DONE:
1026 SET_RETURN( ret );
1027}
1028
1029
1030//================================================================
1033static void c_string_lstrip(struct VM *vm, mrbc_value v[], int argc)
1034{
1035 mrbc_value ret = mrbc_string_dup(vm, &v[0]);
1036
1037 mrbc_string_strip(&ret, 0x01); // 1: left side only
1038
1039 SET_RETURN(ret);
1040}
1041
1042
1043//================================================================
1046static void c_string_lstrip_self(struct VM *vm, mrbc_value v[], int argc)
1047{
1048 if( mrbc_string_strip(&v[0], 0x01) == 0 ) { // 1: left side only
1050 }
1051}
1052
1053
1054//================================================================
1057static void c_string_rstrip(struct VM *vm, mrbc_value v[], int argc)
1058{
1059 mrbc_value ret = mrbc_string_dup(vm, &v[0]);
1060
1061 mrbc_string_strip(&ret, 0x02); // 2: right side only
1062
1063 SET_RETURN(ret);
1064}
1065
1066
1067//================================================================
1070static void c_string_rstrip_self(struct VM *vm, mrbc_value v[], int argc)
1071{
1072 if( mrbc_string_strip(&v[0], 0x02) == 0 ) { // 2: right side only
1074 }
1075}
1076
1077
1078//================================================================
1081static void c_string_strip(struct VM *vm, mrbc_value v[], int argc)
1082{
1083 mrbc_value ret = mrbc_string_dup(vm, &v[0]);
1084
1085 mrbc_string_strip(&ret, 0x03); // 3: left and right
1086
1087 SET_RETURN(ret);
1088}
1089
1090
1091//================================================================
1094static void c_string_strip_self(struct VM *vm, mrbc_value v[], int argc)
1095{
1096 if( mrbc_string_strip(&v[0], 0x03) == 0 ) { // 3: left and right
1098 }
1099}
1100
1101
1102//================================================================
1105static void c_string_to_sym(struct VM *vm, mrbc_value v[], int argc)
1106{
1108
1109 SET_RETURN(ret);
1110}
1111
1112
1113//================================================================
1124 uint8_t type; // 1:in-order, 2:range
1126 int16_t n;
1128 char ch[];
1129};
1130
1131static void tr_free_pattern( struct tr_pattern *pat )
1132{
1133 while( pat ) {
1134 struct tr_pattern *p = pat->next;
1135 mrbc_raw_free( pat );
1136 pat = p;
1137 }
1138}
1139
1140static struct tr_pattern * tr_parse_pattern( struct VM *vm, const mrbc_value *v_pattern, int flag_reverse_enable )
1141{
1142 const char *pattern = mrbc_string_cstr( v_pattern );
1143 int pattern_length = mrbc_string_size( v_pattern );
1144 int flag_reverse = 0;
1145 struct tr_pattern *ret = NULL;
1146
1147 int i = 0;
1148 if( flag_reverse_enable && pattern_length >= 2 && pattern[i] == '^' ) {
1149 flag_reverse = 1;
1150 i++;
1151 }
1152
1153 struct tr_pattern *pat1;
1154 while( i < pattern_length ) {
1155 // is range pattern ?
1156 if( (i+2) < pattern_length && pattern[i+1] == '-' ) {
1157 pat1 = mrbc_alloc( vm, sizeof(struct tr_pattern) + 2 );
1158 if( pat1 != NULL ) {
1159 pat1->type = 2;
1160 pat1->flag_reverse = flag_reverse;
1161 pat1->n = pattern[i+2] - pattern[i] + 1;
1162 pat1->next = NULL;
1163 pat1->ch[0] = pattern[i];
1164 pat1->ch[1] = pattern[i+2];
1165 }
1166 i += 3;
1167
1168 } else {
1169 // in order pattern.
1170 int start_pos = i++;
1171 while( i < pattern_length ) {
1172 if( (i+2) < pattern_length && pattern[i+1] == '-' ) break;
1173 i++;
1174 }
1175
1176 int len = i - start_pos;
1177 pat1 = mrbc_alloc( vm, sizeof(struct tr_pattern) + len );
1178 if( pat1 != NULL ) {
1179 pat1->type = 1;
1180 pat1->flag_reverse = flag_reverse;
1181 pat1->n = len;
1182 pat1->next = NULL;
1183 memcpy( pat1->ch, &pattern[start_pos], len );
1184 }
1185 }
1186
1187 // connect linked list.
1188 if( ret == NULL ) {
1189 ret = pat1;
1190 } else {
1191 struct tr_pattern *p = ret;
1192 while( p->next != NULL ) { p = p->next; }
1193 p->next = pat1;
1194 }
1195 }
1196
1197 return ret;
1198}
1199
1200static int tr_find_character( const struct tr_pattern *pat, int ch )
1201{
1202 int ret = -1;
1203 int n_sum = 0;
1204 int flag_reverse = pat ? pat->flag_reverse : 0;
1205
1206 while( pat != NULL ) {
1207 if( pat->type == 1 ) { // in-order
1208 for( int i = 0; i < pat->n; i++ ) {
1209 if( pat->ch[i] == ch ) ret = n_sum + i;
1210 }
1211 } else { // pat->type == 2 range
1212 if( pat->ch[0] <= ch && ch <= pat->ch[1] ) ret = n_sum + ch - pat->ch[0];
1213 }
1214 n_sum += pat->n;
1215 pat = pat->next;
1216 }
1217
1218 if( flag_reverse ) {
1219 return (ret < 0) ? INT_MAX : -1;
1220 }
1221 return ret;
1222}
1223
1224static int tr_get_character( const struct tr_pattern *pat, int n_th )
1225{
1226 int n_sum = 0;
1227 while( pat != NULL ) {
1228 if( n_th < (n_sum + pat->n) ) {
1229 int i = (n_th - n_sum);
1230 return (pat->type == 1) ? pat->ch[i] :pat->ch[0] + i;
1231 }
1232 if( pat->next == NULL ) {
1233 return (pat->type == 1) ? pat->ch[pat->n - 1] : pat->ch[1];
1234 }
1235 n_sum += pat->n;
1236 pat = pat->next;
1237 }
1238
1239 return -1;
1240}
1241
1242static int tr_main( struct VM *vm, mrbc_value v[], int argc )
1243{
1244 if( !(argc == 2 && mrbc_type(v[1]) == MRBC_TT_STRING &&
1245 mrbc_type(v[2]) == MRBC_TT_STRING)) {
1246 mrbc_raise( vm, MRBC_CLASS(ArgumentError), 0 );
1247 return -1;
1248 }
1249
1250 struct tr_pattern *pat = tr_parse_pattern( vm, &v[1], 1 );
1251 if( pat == NULL ) return 0;
1252
1253 struct tr_pattern *rep = tr_parse_pattern( vm, &v[2], 0 );
1254
1255 int flag_changed = 0;
1256 char *s = mrbc_string_cstr( &v[0] );
1257 int len = mrbc_string_size( &v[0] );
1258
1259 for( int i = 0; i < len; i++ ) {
1260 int n = tr_find_character( pat, s[i] );
1261 if( n < 0 ) continue;
1262
1263 flag_changed = 1;
1264 if( rep == NULL ) {
1265 memmove( s + i, s + i + 1, len - i );
1266 len--;
1267 i--;
1268 } else {
1269 s[i] = tr_get_character( rep, n );
1270 }
1271 }
1272
1273 tr_free_pattern( pat );
1274 tr_free_pattern( rep );
1275
1276 v[0].string->size = len;
1277 v[0].string->data[len] = 0;
1278
1279 return flag_changed;
1280}
1281
1282static void c_string_tr(struct VM *vm, mrbc_value v[], int argc)
1283{
1284 mrbc_value ret = mrbc_string_dup( vm, &v[0] );
1285 SET_RETURN( ret );
1286 tr_main(vm, v, argc);
1287}
1288
1289
1290//================================================================
1293static void c_string_tr_self(struct VM *vm, mrbc_value v[], int argc)
1294{
1295 int flag_changed = tr_main(vm, v, argc);
1296
1297 if( !flag_changed ) {
1299 }
1300}
1301
1302
1303//================================================================
1306static void c_string_start_with(struct VM *vm, mrbc_value v[], int argc)
1307{
1308 if( !(argc == 1 && mrbc_type(v[1]) == MRBC_TT_STRING)) {
1309 mrbc_raise( vm, MRBC_CLASS(ArgumentError), 0 );
1310 return;
1311 }
1312
1313 int ret;
1314 if( mrbc_string_size(&v[0]) < mrbc_string_size(&v[1]) ) {
1315 ret = 0;
1316 } else {
1317 ret = (memcmp( mrbc_string_cstr(&v[0]), mrbc_string_cstr(&v[1]),
1318 mrbc_string_size(&v[1]) ) == 0);
1319 }
1320
1321 SET_BOOL_RETURN(ret);
1322}
1323
1324
1325//================================================================
1328static void c_string_end_with(struct VM *vm, mrbc_value v[], int argc)
1329{
1330 if( !(argc == 1 && mrbc_type(v[1]) == MRBC_TT_STRING)) {
1331 mrbc_raise( vm, MRBC_CLASS(ArgumentError), 0 );
1332 return;
1333 }
1334
1335 int ret;
1336 int offset = mrbc_string_size(&v[0]) - mrbc_string_size(&v[1]);
1337 if( offset < 0 ) {
1338 ret = 0;
1339 } else {
1340 ret = (memcmp( mrbc_string_cstr(&v[0]) + offset, mrbc_string_cstr(&v[1]),
1341 mrbc_string_size(&v[1]) ) == 0);
1342 }
1343
1344 SET_BOOL_RETURN(ret);
1345}
1346
1347
1348//================================================================
1351static void c_string_include(struct VM *vm, mrbc_value v[], int argc)
1352{
1353 if( !(argc == 1 && mrbc_type(v[1]) == MRBC_TT_STRING)) {
1354 mrbc_raise( vm, MRBC_CLASS(ArgumentError), 0 );
1355 return;
1356 }
1357
1358 int ret = mrbc_string_index( &v[0], &v[1], 0 );
1359 SET_BOOL_RETURN(ret >= 0);
1360}
1361
1362
1363//================================================================
1366static void c_string_bytes(struct VM *vm, mrbc_value v[], int argc)
1367{
1368 /*
1369 * Note: This String#bytes doesn't support taking a block parameter.
1370 * Use String#each_byte instead.
1371 */
1372 int len = mrbc_string_size(&v[0]);
1373 mrbc_value ret = mrbc_array_new(vm, len);
1374
1375 for( int i = 0; i < len; i++ ) {
1376 mrbc_array_set(&ret, i, &mrbc_integer_value(v[0].string->data[i]));
1377 }
1378 SET_RETURN(ret);
1379}
1380
1381
1382//================================================================
1385static void c_string_upcase(struct VM *vm, mrbc_value v[], int argc)
1386{
1387 mrbc_value ret = mrbc_string_dup(vm, &v[0]);
1388 mrbc_string_upcase(&ret);
1389 SET_RETURN(ret);
1390}
1391
1392//================================================================
1395static void c_string_upcase_self(struct VM *vm, mrbc_value v[], int argc)
1396{
1397 if (mrbc_string_upcase(&v[0]) == 0) {
1399 }
1400}
1401
1402
1403//================================================================
1406static void c_string_downcase(struct VM *vm, mrbc_value v[], int argc)
1407{
1408 mrbc_value ret = mrbc_string_dup(vm, &v[0]);
1410 SET_RETURN(ret);
1411}
1412
1413
1414//================================================================
1417static void c_string_downcase_self(struct VM *vm, mrbc_value v[], int argc)
1418{
1419 if (mrbc_string_downcase(&v[0]) == 0) {
1421 }
1422}
1423
1424
1425/* MRBC_AUTOGEN_METHOD_TABLE
1426
1427 CLASS("String")
1428 FILE("_autogen_class_string.h")
1429
1430 METHOD( "new", c_string_new )
1431 METHOD( "+", c_string_add )
1432 METHOD( "*", c_string_mul )
1433 METHOD( "size", c_string_size )
1434 METHOD( "length", c_string_size )
1435 METHOD( "to_i", c_string_to_i )
1436 METHOD( "to_s", c_string_to_s )
1437 METHOD( "<<", c_string_append )
1438 METHOD( "[]", c_string_slice )
1439 METHOD( "[]=", c_string_insert )
1440 METHOD( "b", c_ineffect )
1441 METHOD( "clear", c_string_clear )
1442 METHOD( "chomp", c_string_chomp )
1443 METHOD( "chomp!", c_string_chomp_self )
1444 METHOD( "dup", c_string_dup )
1445 METHOD( "empty?", c_string_empty )
1446 METHOD( "getbyte", c_string_getbyte )
1447 METHOD( "setbyte", c_string_setbyte )
1448 METHOD( "index", c_string_index )
1449 METHOD( "inspect", c_string_inspect )
1450 METHOD( "ord", c_string_ord )
1451 METHOD( "slice", c_string_slice )
1452 METHOD( "slice!", c_string_slice_self )
1453 METHOD( "split", c_string_split )
1454 METHOD( "lstrip", c_string_lstrip )
1455 METHOD( "lstrip!", c_string_lstrip_self )
1456 METHOD( "rstrip", c_string_rstrip )
1457 METHOD( "rstrip!", c_string_rstrip_self )
1458 METHOD( "strip", c_string_strip )
1459 METHOD( "strip!", c_string_strip_self )
1460 METHOD( "to_sym", c_string_to_sym )
1461 METHOD( "intern", c_string_to_sym )
1462 METHOD( "tr", c_string_tr )
1463 METHOD( "tr!", c_string_tr_self )
1464 METHOD( "start_with?", c_string_start_with )
1465 METHOD( "end_with?", c_string_end_with )
1466 METHOD( "include?", c_string_include )
1467 METHOD( "bytes", c_string_bytes )
1468 METHOD( "upcase", c_string_upcase )
1469 METHOD( "upcase!", c_string_upcase_self )
1470 METHOD( "downcase", c_string_downcase )
1471 METHOD( "downcase!", c_string_downcase_self )
1472
1473#if MRBC_USE_FLOAT
1474 METHOD( "to_f", c_string_to_f )
1475#endif
1476*/
1477#include "_autogen_class_string.h"
1478
1479
1480#endif // MRBC_USE_STRING
void * mrbc_raw_realloc(void *ptr, unsigned int size)
Definition alloc.c:796
void mrbc_raw_free(void *ptr)
Definition alloc.c:695
int mrbc_array_push(mrbc_value *ary, mrbc_value *set_val)
Definition c_array.c:252
int mrbc_array_set(mrbc_value *ary, int idx, mrbc_value *set_val)
Definition c_array.c:178
mrbc_value mrbc_array_get(const mrbc_value *ary, int idx)
Definition c_array.c:216
mrbc_value mrbc_array_new(struct VM *vm, int size)
Definition c_array.c:82
mrbc_value mrbc_array_remove(mrbc_value *ary, int idx)
Definition c_array.c:397
static int mrbc_array_size(const mrbc_value *ary)
Definition c_array.h:81
static mrbc_value mrbc_range_last(const mrbc_value *v)
Definition c_range.h:72
static int mrbc_range_exclude_end(const mrbc_value *v)
Definition c_range.h:80
static mrbc_value mrbc_range_first(const mrbc_value *v)
Definition c_range.h:64
int mrbc_string_index(const mrbc_value *src, const mrbc_value *pattern, int offset)
Definition c_string.c:269
void mrbc_string_delete(mrbc_value *str)
Definition c_string.c:129
static void tr_free_pattern(struct tr_pattern *pat)
Definition c_string.c:1131
static int tr_get_character(const struct tr_pattern *pat, int n_th)
Definition c_string.c:1224
static int tr_find_character(const struct tr_pattern *pat, int ch)
Definition c_string.c:1200
mrbc_value mrbc_string_dup(struct VM *vm, mrbc_value *s1)
Definition c_string.c:167
static int tr_main(struct VM *vm, mrbc_value v[], int argc)
Definition c_string.c:1242
static int is_space(int ch)
Definition c_string.c:42
static struct tr_pattern * tr_parse_pattern(struct VM *vm, const mrbc_value *v_pattern, int flag_reverse_enable)
Definition c_string.c:1140
void mrbc_string_clear(mrbc_value *str)
Definition c_string.c:140
mrbc_value mrbc_string_add(struct VM *vm, const mrbc_value *s1, const mrbc_value *s2)
Definition c_string.c:188
int mrbc_string_chomp(mrbc_value *src)
Definition c_string.c:334
int mrbc_string_append_cbuf(mrbc_value *s1, const void *s2, int len2)
Definition c_string.c:240
int mrbc_string_upcase(mrbc_value *str)
Definition c_string.c:363
int mrbc_string_downcase(mrbc_value *str)
Definition c_string.c:385
int mrbc_string_append(mrbc_value *s1, const mrbc_value *s2)
Definition c_string.c:210
mrbc_value mrbc_string_new(struct VM *vm, const void *src, int len)
Definition c_string.c:62
mrbc_value mrbc_string_new_alloc(struct VM *vm, void *buf, int len)
Definition c_string.c:105
int mrbc_string_strip(mrbc_value *src, int mode)
Definition c_string.c:294
struct RString mrbc_string
String object.
static char * mrbc_string_cstr(const mrbc_value *v)
Definition c_string.h:116
static mrbc_value mrbc_string_new_cstr(struct VM *vm, const char *src)
Definition c_string.h:85
static int mrbc_string_append_cstr(mrbc_value *s1, const char *s2)
Definition c_string.h:128
static int mrbc_string_size(const mrbc_value *str)
Definition c_string.h:108
#define MRBC_CLASS(cls)
Definition class.h:51
void mrbc_raise(struct VM *vm, struct RClass *exc_cls, const char *msg)
Definition error.c:150
void mrbc_raisef(struct VM *vm, struct RClass *exc_cls, const char *fstr,...)
Definition error.c:173
Include at once the necessary header files.
struct RString * string
Definition value.h:164
mrbc_vtype tt
Definition value.h:152
mrbc_int_t i
Definition value.h:154
uint8_t * data
pointer to allocated buffer.
Definition c_string.h:51
MRBC_STRING_SIZE_T size
string length.
Definition c_string.h:50
Virtual Machine.
Definition vm.h:140
int16_t n
Definition c_string.c:1126
uint8_t flag_reverse
Definition c_string.c:1125
char ch[]
Definition c_string.c:1128
struct tr_pattern * next
Definition c_string.c:1127
uint8_t type
Definition c_string.c:1124
mrbc_value mrbc_symbol_new(struct VM *vm, const char *str)
Definition symbol.c:334
const char * mrbc_symid_to_str(mrbc_sym sym_id)
Definition symbol.c:238
mrbc_int_t mrbc_atoi(const char *s, int base)
Definition value.c:186
float mrbc_float_t
Definition value.h:51
int32_t mrbc_int_t
Definition value.h:45
static void mrbc_decref(mrbc_value *v)
Definition value.h:604
#define MRBC_INIT_OBJECT_HEADER(p, t)
Definition value.h:307
#define SET_BOOL_RETURN(n)
Definition value.h:278
#define SET_INT_RETURN(n)
Definition value.h:283
#define mrbc_nil_value()
Definition value.h:210
#define SET_NIL_RETURN()
Definition value.h:266
static void mrbc_incref(mrbc_value *v)
Definition value.h:589
@ E_NOMEMORY_ERROR
Definition value.h:108
#define mrbc_type(o)
Definition value.h:193
@ MRBC_TT_STRING
String.
Definition value.h:95
@ MRBC_TT_INTEGER
Integer.
Definition value.h:83
@ MRBC_TT_EMPTY
Definition value.h:77
@ MRBC_TT_RANGE
Range.
Definition value.h:96
@ MRBC_TT_NIL
NilClass.
Definition value.h:78
@ MRBC_TT_CLASS
Class.
Definition value.h:87
struct RObject mrbc_value
Definition value.h:174
#define SET_RETURN(n)
Definition value.h:261
#define mrbc_integer(o)
Definition value.h:194
#define mrbc_integer_value(n)
Definition value.h:208
#define SET_FLOAT_RETURN(n)
Definition value.h:289
Global configuration of mruby/c VM's.