1 //metadoc Sequence category Core
2 //metadoc Sequence copyright Steve Dekorte 2002
3 //metadoc Sequence license BSD revised
4 /*metadoc Sequence description
5 A Sequence is a container for a list of data elements.
6 Immutable Sequences are also called "Symbols".
7 */
8
9 #include "IoSeq.h"
10 #include "IoState.h"
11 #include "IoCFunction.h"
12 #include "IoObject.h"
13 #include "IoNumber.h"
14 #include "IoMessage.h"
15 #include "IoList.h"
16 #include <ctype.h>
17 #include <errno.h>
18 #include "parson.h"
19 #include "IoMap.h"
20
21 #define DATA(self) ((UArray *)IoObject_dataPointer(self))
22
23
IoSeq_rawAsSymbol(IoSeq * self)24 IoObject *IoSeq_rawAsSymbol(IoSeq *self)
25 {
26 if (ISSYMBOL(self))
27 {
28 return self;
29 }
30
31 return IoState_symbolWithUArray_copy_(IOSTATE, DATA(self), 1);
32 }
33
IO_METHOD(IoSeq,with)34 IO_METHOD(IoSeq, with)
35 {
36 /*doc Sequence with(aSequence, ...)
37 Returns a new Sequence which is the concatenation of the arguments.
38 The returned sequence will have the same mutability status as the receiver.
39 */
40
41 int n, argCount = IoMessage_argCount(m);
42 UArray *ba = UArray_clone(DATA(self));
43
44 for (n = 0; n < argCount; n ++)
45 {
46 IoSeq *v = IoMessage_locals_seqArgAt_(m, locals, n);
47 UArray_append_(ba, DATA(v));
48 }
49
50 if (ISSYMBOL(self))
51 {
52 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
53 }
54
55 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
56 }
57
IO_METHOD(IoSeq,itemType)58 IO_METHOD(IoSeq, itemType)
59 {
60 /*doc Sequence itemType
61 Returns machine type of elements.
62 */
63
64 return IOSYMBOL(CTYPE_name(UArray_itemType(DATA(self))));
65 }
66
IO_METHOD(IoSeq,itemSize)67 IO_METHOD(IoSeq, itemSize)
68 {
69 /*doc Sequence itemSize
70 Returns number of bytes in each element.
71 */
72
73 return IONUMBER(UArray_itemSize(DATA(self)));
74 }
75
IO_METHOD(IoSeq,encoding)76 IO_METHOD(IoSeq, encoding)
77 {
78 /*doc Sequence encoding
79 Returns the encoding of the elements.
80 */
81
82 return IOSYMBOL(CENCODING_name(UArray_encoding(DATA(self))));
83 }
84
IO_METHOD(IoSeq,asUTF8)85 IO_METHOD(IoSeq, asUTF8)
86 {
87 /*doc Sequence asUTF8
88 Returns a new copy of the receiver converted to utf8 encoding.
89 */
90
91 return IoSeq_newWithUArray_copy_(IOSTATE, UArray_asUTF8(DATA(self)), 0);
92 }
93
IO_METHOD(IoSeq,asUCS2)94 IO_METHOD(IoSeq, asUCS2)
95 {
96 /*doc Sequence asUCS2
97 Returns a new copy of the receiver converted to UCS2 (fixed character width UTF16) encoding.
98 */
99
100 return IoSeq_newWithUArray_copy_(IOSTATE, UArray_asUCS2(DATA(self)), 0);
101 }
102
IO_METHOD(IoSeq,asUCS4)103 IO_METHOD(IoSeq, asUCS4)
104 {
105 /*doc Sequence asUCS4
106 Returns a new copy of the receiver converted to UCS4 (fixed character width UTF32) encoding.
107 */
108
109 return IoSeq_newWithUArray_copy_(IOSTATE, UArray_asUCS4(DATA(self)), 0);
110 }
111
IO_METHOD(IoSeq,asFixedSizeType)112 IO_METHOD(IoSeq, asFixedSizeType)
113 {
114 /*doc Sequence asFixedSizeType
115 Returns a new sequence with the receiver encoded in the
116 minimal fixed width text encoding that its characters can fit
117 into (either, ascii, utf8, utf16 or utf32).
118 */
119
120 UArray *out = UArray_new();
121 UArray_copy_(out, DATA(self));
122 UArray_convertToFixedSizeType(out);
123 return IoSeq_newWithUArray_copy_(IOSTATE, out, 0);
124 }
125
IO_METHOD(IoSeq,asBinaryUnsignedInteger)126 IO_METHOD(IoSeq, asBinaryUnsignedInteger)
127 {
128 /*doc Sequence asBinaryUnsignedInteger
129 Returns a Number with the bytes of the receiver interpreted as a binary unsigned integer. Endian is same as machine.
130 */
131
132 const void *bytes = UArray_bytes(DATA(self));
133 size_t byteCount = UArray_size(DATA(self));
134
135 if(byteCount == 1)
136 {
137 return IONUMBER(*((const uint8_t *)bytes));
138 }
139 else if(byteCount == 2)
140 {
141 return IONUMBER(*((const uint16_t *)bytes));
142 }
143 else if(byteCount == 4)
144 {
145 return IONUMBER(*((const uint32_t *)bytes));
146 }
147 else
148 {
149 IoState_error_(IOSTATE, m, "Sequence is %i bytes but only conversion of 1, 2, or 4 bytes is supported", byteCount);
150 }
151
152 return IONIL(self);
153 }
154
IO_METHOD(IoSeq,asBinarySignedInteger)155 IO_METHOD(IoSeq, asBinarySignedInteger)
156 {
157 /*doc Sequence asBinarySignedInteger
158 Returns a Number with the bytes of the receiver interpreted as a binary signed integer. Endian is same as machine.
159 */
160
161 const void *bytes = UArray_bytes(DATA(self));
162 size_t byteCount = UArray_size(DATA(self));
163
164 if(byteCount == 1)
165 {
166 return IONUMBER(*((const int8_t *)bytes));
167 }
168 else if(byteCount == 2)
169 {
170 return IONUMBER(*((const int16_t *)bytes));
171 }
172 else if(byteCount == 4)
173 {
174 return IONUMBER(*((const int32_t *)bytes));
175 }
176 else
177 {
178 IoState_error_(IOSTATE, m, "Sequence is %i bytes but only conversion of 1, 2, or 4 bytes is supported", byteCount);
179 }
180
181 return IONIL(self);
182 }
183
184
IO_METHOD(IoSeq,asBinaryNumber)185 IO_METHOD(IoSeq, asBinaryNumber)
186 {
187 /*doc Sequence asBinaryNumber
188 Returns a Number containing the first 8 bytes of the
189 receiver without casting them to a double. Endian is same as machine.
190 */
191
192 IoNumber *byteCount = IoMessage_locals_valueArgAt_(m, locals, 0);
193 size_t max = UArray_size(DATA(self));
194 int bc = sizeof(double);
195 double d = 0;
196
197 if (!ISNIL(byteCount))
198 {
199 bc = IoNumber_asInt(byteCount);
200 }
201
202 if (max < bc)
203 {
204 IoState_error_(IOSTATE, m, "requested first %i bytes, but Sequence only contains %i bytes", bc, max);
205 }
206
207 memcpy(&d, UArray_bytes(DATA(self)), bc);
208 return IONUMBER(d);
209 }
210
IO_METHOD(IoSeq,asSymbol)211 IO_METHOD(IoSeq, asSymbol)
212 {
213 /*doc Sequence asSymbol
214 Returns a immutable Sequence (aka Symbol) version of the receiver.
215 */
216
217 return IoSeq_rawAsSymbol(self);
218 }
219
IO_METHOD(IoSeq,isSymbol)220 IO_METHOD(IoSeq, isSymbol)
221 {
222 /*doc Sequence isSymbol
223 Returns true if the receiver is a
224 immutable Sequence (aka, a Symbol) or false otherwise.
225 */
226
227 return IOBOOL(self, ISSYMBOL(self));
228 }
229
IO_METHOD(IoSeq,isMutable)230 IO_METHOD(IoSeq, isMutable)
231 {
232 /*doc Sequence isMutable
233 Returns true if the receiver is a mutable Sequence or false otherwise.
234 */
235
236 return IOBOOL(self, !ISSYMBOL(self));
237 }
238
239
IO_METHOD(IoSeq,print)240 IO_METHOD(IoSeq, print)
241 {
242 /*doc Sequence print
243 Prints the receiver as a string. Returns self.
244 */
245
246 IoState_justPrintba_(IOSTATE, DATA(self));
247 return self;
248 }
249
IO_METHOD(IoSeq,linePrint)250 IO_METHOD(IoSeq, linePrint)
251 {
252 /*doc Sequence linePrint
253 Prints the Sequence and a newline character.
254 */
255
256 IoState_justPrintba_(IOSTATE, DATA(self));
257 IoState_justPrintln_(IOSTATE);
258 return self;
259 }
260
261 //
262 // Sequence parseJson
263 //
264
265 static IoObject* parse_json_value(IoObject* self, JSON_Value* value);
266 static IoMap* parse_json_object(IoObject* self, JSON_Object* object);
267 static IoList* parse_json_array(IoObject* self, JSON_Array* array);
268
IO_METHOD(IoSeq,parseJson)269 IOVM_API IO_METHOD(IoSeq, parseJson) {
270 /*doc Sequence parseJson
271 Interprets the Sequence as JSON and returns a Map.
272 */
273 IoMap* result;
274 JSON_Value* output;
275 char* value = IoSeq_asCString(self);
276
277 if(IoSeq_rawSizeInBytes(self) == 0)
278 IoState_error_(IOSTATE, m, "Can't parse empty string.");
279
280 output = json_parse_string_with_comments(value);
281
282 if(!output)
283 IoState_error_(IOSTATE, m, "Can't parse JSON.");
284
285 result = parse_json_object(self, json_object(output));
286
287 json_value_free(output);
288
289 return result;
290 }
291
parse_json_object(IoObject * self,JSON_Object * object)292 IoMap* parse_json_object(IoObject* self, JSON_Object* object) {
293 IoMap* map = IoMap_new(IOSTATE);
294 IoObject* value;
295 char* key;
296 size_t num_of_keys = json_object_get_count(object);
297 size_t i;
298
299 for(i = 0; i < num_of_keys; i++) {
300 key = (char*) json_object_get_name(object, i);
301 value = parse_json_value(self, json_object_get_value(object, key));
302 IoMap_rawAtPut(map, IOSYMBOL(key), value);
303 }
304
305 return map;
306 }
307
parse_json_value(IoObject * self,JSON_Value * value)308 IoObject* parse_json_value(IoObject* self, JSON_Value* value) {
309 switch(json_type(value)) {
310 case JSONError:
311 return 0;
312 case JSONNull:
313 return IOSTATE->ioNil;
314 case JSONString:
315 return IoSeq_newWithCString_(IOSTATE, json_string(value));
316 case JSONNumber:
317 return IoNumber_newWithDouble_(IOSTATE, json_value_get_number(value));
318 case JSONObject:
319 return parse_json_object(self, json_object(value));
320 case JSONArray:
321 return parse_json_array(self, json_array(value));
322 case JSONBoolean:
323 return IOBOOL(self, json_boolean(value));
324 default:
325 return 0;
326 }
327 }
328
parse_json_array(IoObject * self,JSON_Array * array)329 IoList* parse_json_array(IoObject* self, JSON_Array* array) {
330 IoList* list = IoList_new(IOSTATE);
331 IoObject* value;
332 size_t num_of_elements = json_array_get_count(array);
333 size_t i;
334
335 for(i = 0; i < num_of_elements; i++) {
336 value = parse_json_value(self, json_array_get_value(array, i));
337 IoList_rawAppend_(list, value);
338 }
339
340 return list;
341 }
342
343 //--------------------------------------
344
IO_METHOD(IoSeq,isEmpty)345 IO_METHOD(IoSeq, isEmpty)
346 {
347 /*doc Sequence isEmpty
348 Returns true if the size of the receiver is 0, false otherwise.
349 */
350
351 return IOBOOL(self, UArray_size(DATA(self)) == 0);
352 }
353
IO_METHOD(IoSeq,isZero)354 IO_METHOD(IoSeq, isZero)
355 {
356 /*doc Sequence isZero
357 Returns true if all elements are 0, false otherwise.
358 */
359
360 return IOBOOL(self, UArray_isZero(DATA(self)));
361 }
362
IO_METHOD(IoSeq,size)363 IO_METHOD(IoSeq, size)
364 {
365 /*doc Sequence size
366 Returns the length in number of items (which may or may not
367 be the number of bytes, depending on the item type) of the receiver. For example:
368 <p>
369 <pre>
370 "abc" size == 3
371 </pre>
372 */
373
374 return IONUMBER(UArray_size(DATA(self)));
375 }
376
IO_METHOD(IoSeq,sizeInBytes)377 IO_METHOD(IoSeq, sizeInBytes)
378 {
379 /*doc Sequence sizeInBytes
380 Returns the length in bytes of the receiver.
381 */
382
383 return IONUMBER(UArray_sizeInBytes(DATA(self)));
384 }
385
386
IO_METHOD(IoSeq,at)387 IO_METHOD(IoSeq, at)
388 {
389 /*doc Sequence at(aNumber)
390 Returns a value at the index specified by aNumber.
391 Returns nil if the index is out of bounds.
392 */
393
394 size_t i = IoMessage_locals_sizetArgAt_(m, locals, 0);
395 UArray *a = DATA(self);
396
397 //IOASSERT((i < UArray_size(DATA(self))), "index out of bounds");
398 if(i >= UArray_size(DATA(self))) return IONIL(self);
399
400 if(UArray_isFloatType(a))
401 {
402 return IONUMBER(UArray_doubleAt_(a, i));
403 }
404 else
405 {
406 return IONUMBER(UArray_longAt_(a, i));
407 }
408 }
409
IO_METHOD(IoSeq,exclusiveSlice)410 IO_METHOD(IoSeq, exclusiveSlice)
411 {
412 /*doc Sequence exclusiveSlice(inclusiveStartIndex, exclusiveEndIndex)
413 Returns a new string containing the subset of the
414 receiver from the inclusiveStartIndex to the exclusiveEndIndex. The exclusiveEndIndex argument
415 is optional. If not given, it is assumed to be one beyond the end of the string.
416 */
417
418 long fromIndex = IoMessage_locals_longArgAt_(m, locals, 0);
419 long last = UArray_size(DATA(self));
420 UArray *ba;
421
422 if (IoMessage_argCount(m) > 1)
423 {
424 last = IoMessage_locals_longArgAt_(m, locals, 1);
425 }
426
427 ba = UArray_slice(DATA(self), fromIndex, last);
428
429 if (ISSYMBOL(self))
430 {
431 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
432 }
433
434 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
435 }
436
IO_METHOD(IoSeq,inclusiveSlice)437 IO_METHOD(IoSeq, inclusiveSlice)
438 {
439 /*doc Sequence inclusiveSlice(inclusiveStartIndex, inclusiveEndIndex)
440 Returns a new string containing the subset of the
441 receiver from the inclusiveStartIndex to the inclusiveEndIndex. The inclusiveEndIndex argument
442 is optional. If not given, it is assumed to be the end of the string.
443 */
444
445 long fromIndex = IoMessage_locals_longArgAt_(m, locals, 0);
446 long last = UArray_size(DATA(self));
447 UArray *ba;
448
449 if (IoMessage_argCount(m) > 1)
450 {
451 last = IoMessage_locals_longArgAt_(m, locals, 1);
452 }
453
454 if (last == -1)
455 {
456 last = UArray_size(DATA(self));
457 }
458 else
459 {
460 last = last + 1;
461 }
462
463 ba = UArray_slice(DATA(self), fromIndex, last);
464
465 if (ISSYMBOL(self))
466 {
467 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
468 }
469
470 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
471 }
472
IO_METHOD(IoSeq,between)473 IO_METHOD(IoSeq, between)
474 {
475 /*doc Sequence betweenSeq(aSequence, anotherSequence)
476 Returns a new Sequence containing the bytes between the
477 occurrence of aSequence and anotherSequence in the receiver.
478 If aSequence is empty, this method is equivalent to beforeSeq(anotherSequence).
479 If anotherSequence is nil, this method is equivalent to afterSeq(aSequence).
480 nil is returned if no match is found.
481 */
482
483 long start = 0;
484 long end = 0;
485 IoSeq *fromSeq, *toSeq;
486
487 fromSeq = (IoSeq *)IoMessage_locals_valueArgAt_(m, locals, 0);
488
489 if (ISSEQ(fromSeq))
490 {
491 if (IoSeq_rawSize(fromSeq) == 0)
492 {
493 start = 0;
494 }
495 else
496 {
497 start = UArray_find_from_(DATA(self), DATA(fromSeq), 0);
498
499 if (start == -1)
500 {
501 //start = 0;
502 return IONIL(self);
503 }
504 start += IoSeq_rawSize(fromSeq);
505 }
506 }
507 else if (ISNIL(fromSeq))
508 {
509 start = 0;
510 }
511 else
512 {
513 IoState_error_(IOSTATE, m, "Nil or Sequence argument required for arg 0, not a %s",
514 IoObject_name((IoObject *)fromSeq));
515 }
516
517 toSeq = (IoSeq *)IoMessage_locals_valueArgAt_(m, locals, 1);
518
519 if (ISSEQ(toSeq))
520 {
521 end = UArray_find_from_(DATA(self), DATA(toSeq), start);
522 //if (end == -1) start = UArray_size(DATA(self));
523 if (end == -1) return IONIL(self);
524 }
525 else if (ISNIL(toSeq))
526 {
527 end = UArray_size(DATA(self));
528 }
529 else
530 {
531 IoState_error_(IOSTATE, m, "Nil or Sequence argument required for arg 1, not a %s",
532 IoObject_name((IoObject *)toSeq));
533 }
534
535 {
536 UArray *ba = UArray_slice(DATA(self), start, end);
537 IoSeq *result = IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
538 return result;
539 }
540 }
541
542 // find ----------------------------------------------------------
543
IO_METHOD(IoSeq,findSeqs)544 IO_METHOD(IoSeq, findSeqs)
545 {
546 /*doc Sequence findSeqs(listOfSequences, optionalStartIndex)
547 Returns an object with two slots - an \"index\" slot which contains
548 the first occurrence of any of the sequences in listOfSequences found
549 in the receiver after the startIndex, and a \"match\" slot, which
550 contains a reference to the matching sequence from listOfSequences.
551 If no startIndex is specified, the search starts at index 0.
552 nil is returned if no occurrences are found.
553 */
554
555 IoList *others = IoMessage_locals_listArgAt_(m, locals, 0);
556 List *delims = IoList_rawList(others);
557 long f = 0;
558 long firstIndex = -1;
559 size_t match = 0;
560
561 if (IoMessage_argCount(m) > 1)
562 {
563 f = IoMessage_locals_longArgAt_(m, locals, 1);
564 }
565
566 {
567 size_t index;
568
569 LIST_FOREACH(delims, i, s,
570 if (!ISSEQ((IoSeq *)s))
571 {
572 IoState_error_(IOSTATE, m, "requires Sequences as arguments, not %ss", IoObject_name((IoSeq *)s));
573 }
574
575 index = UArray_find_from_(DATA(self), DATA(((IoSeq *)s)), f);
576
577 if(index != -1 && (firstIndex == -1 || index < firstIndex))
578 {
579 firstIndex = (long)index;
580 match = i;
581 }
582 );
583 }
584
585 if (firstIndex == -1)
586 {
587 return IONIL(self);
588 }
589 else
590 {
591 IoObject *result = IoObject_new(IOSTATE);
592 IoObject_setSlot_to_(result, IOSYMBOL("index"), IONUMBER(firstIndex));
593 IoObject_setSlot_to_(result, IOSYMBOL("match"), (IoObject *)List_at_(delims, match));
594 return result;
595 }
596 }
597
598
IO_METHOD(IoSeq,findSeq)599 IO_METHOD(IoSeq, findSeq)
600 {
601 /*doc Sequence findSeq(aSequence, optionalStartIndex)
602 Returns a number with the first occurrence of aSequence in
603 the receiver after the startIndex. If no startIndex is specified,
604 the search starts at index 0.
605 nil is returned if no occurrences are found.
606 */
607
608 IoSeq *otherSequence = IoMessage_locals_seqArgAt_(m, locals, 0);
609 long f = 0;
610 long index;
611
612 if (IoMessage_argCount(m) > 1)
613 {
614 f = IoMessage_locals_longArgAt_(m, locals, 1);
615 }
616
617 index = UArray_find_from_(DATA(self), DATA(otherSequence), f);
618
619 return (index == -1) ? IONIL(self) : IONUMBER(index);
620 }
621
IO_METHOD(IoSeq,reverseFindSeq)622 IO_METHOD(IoSeq, reverseFindSeq)
623 {
624 /*doc Sequence reverseFindSeq(aSequence, startIndex)
625 Returns a number with the first occurrence of aSequence in
626 the receiver before the startIndex. The startIndex argument is optional.
627 By default reverseFind starts at the end of the string. Nil is
628 returned if no occurrences are found.
629 */
630
631 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
632 long from = UArray_size(DATA(self));
633 long index;
634
635 if (IoMessage_argCount(m) > 1)
636 {
637 from = IoMessage_locals_intArgAt_(m, locals, 1);
638 }
639
640 index = UArray_rFind_from_(DATA(self), DATA(other), from);
641
642 if (index == -1)
643 {
644 return IONIL(self);
645 }
646
647 return IONUMBER((double)index);
648 }
649
IO_METHOD(IoSeq,beginsWithSeq)650 IO_METHOD(IoSeq, beginsWithSeq)
651 {
652 /*doc Sequence beginsWithSeq(aSequence)
653 Returns true if the receiver begins with aSequence, false otherwise.
654 */
655
656 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
657
658 return IOBOOL(self, UArray_beginsWith_(DATA(self), DATA(other)));
659 }
660
IO_METHOD(IoSeq,endsWithSeq)661 IO_METHOD(IoSeq, endsWithSeq)
662 {
663 /*doc Sequence endsWithSeq(aSequence)
664 Returns true if the receiver ends with aSequence, false otherwise.
665 */
666
667 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
668 return IOBOOL(self, UArray_endsWith_(DATA(self), DATA(other)));
669 }
670
IO_METHOD(IoSeq,contains)671 IO_METHOD(IoSeq, contains)
672 {
673 /*doc Sequence contains(aNumber)
674 Returns true if the receiver contains an element equal in value to aNumber, false otherwise.
675 */
676
677 // will make this more efficient when Numbers are Arrays
678
679 IoNumber *n = IoMessage_locals_numberArgAt_(m, locals, 0);
680
681 UArray tmp = IoNumber_asStackUArray(n);
682 return IOBOOL(self, UArray_contains_(DATA(self), &tmp));
683 }
684
IO_METHOD(IoSeq,containsSeq)685 IO_METHOD(IoSeq, containsSeq)
686 {
687 /*doc Sequence containsSeq(aSequence)
688 Returns true if the receiver contains the substring
689 aSequence, false otherwise.
690 */
691
692 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
693
694 return IOBOOL(self, UArray_contains_(DATA(self), DATA(other)));
695 }
696
IO_METHOD(IoSeq,containsAnyCaseSeq)697 IO_METHOD(IoSeq, containsAnyCaseSeq)
698 {
699 /*doc Sequence containsAnyCaseSeq(aSequence)
700 Returns true if the receiver contains the aSequence
701 regardless of casing, false otherwise.
702 */
703
704 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
705 return IOBOOL(self, UArray_containsAnyCase_(DATA(self), DATA(other)));
706 }
707
IO_METHOD(IoSeq,isLowercase)708 IO_METHOD(IoSeq, isLowercase)
709 {
710 /*doc Sequence isLowercase
711 Returns self if all the characters in the string are lower case.
712 */
713
714 return IOBOOL(self, UArray_isLowercase(DATA(self)));
715 }
716
IO_METHOD(IoSeq,isUppercase)717 IO_METHOD(IoSeq, isUppercase)
718 {
719 /*doc Sequence isUppercase
720 Returns self if all the characters in the string are upper case.
721 */
722
723 return IOBOOL(self, UArray_isUppercase(DATA(self)));
724 }
725
IO_METHOD(IoSeq,isEqualAnyCase)726 IO_METHOD(IoSeq, isEqualAnyCase)
727 {
728 /*doc Sequence isEqualAnyCase(aSequence)
729 Returns true if aSequence is equal to the receiver
730 ignoring case differences, false otherwise.
731 */
732
733 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
734
735 return IOBOOL(self, UArray_equalsAnyCase_(DATA(self), DATA(other)));
736 }
737
IO_METHOD(IoSeq,asNumber)738 IO_METHOD(IoSeq, asNumber)
739 {
740 /*doc Sequence asNumber
741 Returns the receiver converted to a number.
742 Initial whitespace is ignored.
743 */
744
745 size_t size = UArray_size(DATA(self));
746 char *s = (char *)UArray_bytes(DATA(self));
747 char *endp;
748 double d = strtod(s, &endp);
749
750 if (size > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
751 {
752 return IONUMBER(IoSeq_rawAsDoubleFromHex(self));
753 }
754
755 if (errno == ERANGE || endp == s)
756 {
757 return IONUMBER(NAN);
758 }
759
760 return IONUMBER(d);
761 }
762
IO_METHOD(IoSeq,asList)763 IO_METHOD(IoSeq, asList)
764 {
765 /*doc Sequence asList
766 Returns the receiver converted to a List containing all elements of the Sequence.
767 */
768
769 List *list = List_new();
770
771 size_t i;
772
773 for (i = 0; i < UArray_size(DATA(self)); i++)
774 {
775 if(UArray_isFloatType(DATA(self)))
776 {
777 List_append_(list, IONUMBER(UArray_doubleAt_(DATA(self), i)));
778 }
779 else
780 {
781 long c = UArray_longAt_(DATA(self), i);
782 List_append_(list, IOSYMBOL(&c));
783 }
784 }
785
786 return IoList_newWithList_(IOSTATE, list);
787 }
788
IoSeq_whiteSpaceStrings(IoSeq * self,IoObject * locals,IoMessage * m)789 IoList *IoSeq_whiteSpaceStrings(IoSeq *self, IoObject *locals, IoMessage *m)
790 {
791 /*doc Sequence whiteSpaceStrings
792 Returns a List of strings. Each string contains a different
793 whitespace character.
794 */
795
796 IoList *strings = IoList_new(IOSTATE);
797 IoList_rawAppend_(strings, IOSYMBOL(" "));
798 IoList_rawAppend_(strings, IOSYMBOL("\t"));
799 IoList_rawAppend_(strings, IOSYMBOL("\n"));
800 IoList_rawAppend_(strings, IOSYMBOL("\r"));
801 return strings;
802 }
803
804 // split ---------------------------------------------------------------------
805
806 // this method is only used from split
IoSeq_stringListForArgs(IoSeq * self,IoObject * locals,IoMessage * m)807 IoList *IoSeq_stringListForArgs(IoSeq *self, IoObject *locals, IoMessage *m)
808 {
809 if (IoMessage_argCount(m) == 0)
810 {
811 return IoSeq_whiteSpaceStrings(self, locals, m);
812 }
813
814 return IoMessage_evaluatedArgs(m, locals, m);
815 }
816
817 // this method is only used from split
IoSeq_byteArrayListForSeqList(IoSeq * self,IoObject * locals,IoMessage * m,IoList * seqs)818 List *IoSeq_byteArrayListForSeqList(IoSeq *self, IoObject *locals, IoMessage *m, IoList *seqs)
819 {
820 List *args = IoList_rawList(seqs);
821 List *list = List_new();
822
823 LIST_FOREACH(args, i, s,
824 if (!ISSEQ((IoSeq *)s))
825 {
826 List_free(list);
827 IoState_error_(IOSTATE, m,
828 "requires Sequences as arguments, not %ss",
829 IoObject_name((IoSeq *)s));
830 }
831
832 List_append_(list, DATA(((IoSeq *)s)));
833 );
834
835 return list;
836 }
837
IoSeq_splitToFunction(IoSeq * self,IoObject * locals,IoMessage * m,IoSplitFunction * func)838 IoObject *IoSeq_splitToFunction(IoSeq *self,
839 IoObject *locals,
840 IoMessage *m,
841 IoSplitFunction *func)
842 {
843 IoList *output = IoList_new(IOSTATE);
844 List *others = IoSeq_byteArrayListForSeqList(self, locals, m, IoSeq_stringListForArgs(self, locals, m));
845 int i;
846
847 for (i = 0; i < List_size(others); i ++)
848 {
849 if (UArray_size(List_at_(others, i)) == 0)
850 {
851 IoState_error_(IOSTATE, m, "empty string argument");
852 }
853 }
854
855 {
856 UArray othersArray = List_asStackAllocatedUArray(others);
857 UArray *results = UArray_split_(DATA(self), &othersArray);
858
859 for (i = 0; i < UArray_size(results); i ++)
860 {
861 UArray *ba = UArray_pointerAt_(results, i);
862 IoObject *item = (*func)(IOSTATE, ba, 0);
863 IoList_rawAppend_(output, item);
864 }
865
866 UArray_free(results);
867 }
868
869 List_free(others);
870 return output;
871 }
872
IO_METHOD(IoSeq,split)873 IO_METHOD(IoSeq, split)
874 {
875 /*doc Sequence split(optionalArg1, optionalArg2, ...)
876 Returns a list containing the sub-sequences of the receiver divided by the given arguments.
877 If no arguments are given the sequence is split on white space.
878 Examples:
879 <pre>
880 "a b c d" split == list("a", "b", "c", "d")
881 "a*b*c*d" split("*") == list("a", "b", "c", "d")
882 "a*b|c,d" split("*", "|", ",") == list("a", "b", "c", "d")
883 "a b c d" split == list("a", "", "", "", "b", "", "", "c", "", "d")
884 </pre>
885 */
886
887 return IoSeq_splitToFunction(self, locals, m, IoSeq_newWithUArray_copy_);
888 }
889
IO_METHOD(IoSeq,splitAt)890 IO_METHOD(IoSeq, splitAt)
891 {
892 /*doc Sequence splitAt(indexNumber)
893 Returns a list containing the two parts of the receiver as split at the given index.
894 */
895
896 size_t index = IoMessage_locals_intArgAt_(m, locals, 0);
897 IoList *splitSeqs = IoList_new(IOSTATE);
898 index = UArray_wrapPos_(DATA(self), index);
899
900 {
901 const char *s = UArray_asCString(DATA(self));
902 IoSeq *s1 = IoState_symbolWithCString_length_(IOSTATE, s, index);
903 IoSeq *s2 = IoState_symbolWithCString_(IOSTATE, s + index);
904 IoList_rawAppend_(splitSeqs, (IoObject *)s1);
905 IoList_rawAppend_(splitSeqs, (IoObject *)s2);
906 }
907
908 return splitSeqs;
909 }
910
911 /* --- base -------------------------------------------------------------- */
912
IO_METHOD(IoSeq,fromBase)913 IO_METHOD(IoSeq, fromBase)
914 {
915 /*doc Sequence fromBase(aNumber)
916 Returns a number with a base 10 representation of the receiver
917 converted from the specified base. Only base 2 through 32 are currently supported.
918 */
919
920 int base = IoMessage_locals_intArgAt_(m, locals, 0);
921 char *s = CSTRING(self);
922 unsigned long r;
923 char *tail;
924 errno = 0;
925 r = strtoul(s, &tail, base);
926
927 if (errno == EINVAL)
928 {
929 errno = 0;
930 IoState_error_(IOSTATE, m, "conversion from base %i not supported", base);
931 }
932 else if (errno == ERANGE)
933 {
934 errno = 0;
935 IoState_error_(IOSTATE, m, "resulting value \"%s\" was out of range", s);
936 }
937 else if (*s == 0 || *tail != 0 || errno != 0)
938 {
939 errno = 0;
940 IoState_error_(IOSTATE, m, "conversion of \"%s\" to base %i failed", s, base);
941 }
942
943 return IONUMBER(r);
944 }
945
IO_METHOD(IoSeq,toBase)946 IO_METHOD(IoSeq, toBase)
947 {
948 /*doc Sequence toBase(aNumber)
949 Returns a Sequence containing the receiver (which is
950 assumed to be a base 10 number) converted to the specified base.
951 Only base 8 and 16 are currently supported.
952 */
953
954 const char * const table = "0123456789abcdefghijklmnopqrstuvwxyz";
955 int base = IoMessage_locals_intArgAt_(m, locals, 0);
956 char buf[64], *ptr = buf + 64;
957 unsigned long n = 0;
958
959 if (base < 2 || base > 36)
960 {
961 IoState_error_(IOSTATE, m, "conversion to base %i not supported", base);
962 }
963
964 #if defined(_MSC_VER) || defined(__MINGW32__)
965 n = strtoul(IoSeq_asCString(self), NULL, 0);
966 #else
967 n = (unsigned long) IoSeq_asDouble(self);
968 #endif
969
970 /* Build the converted string backwards. */
971 *(--ptr) = '\0';
972
973 if (n == 0)
974 {
975 *(--ptr) = '0';
976 }
977 else
978 {
979 do
980 {
981 *(--ptr) = table[n % base];
982 }
983 while ((n /= base) != 0);
984 }
985
986 return IoSeq_newWithCString_(IOSTATE, ptr);
987 }
988
989 // this function is only called by IoSeq_foreach()
IO_METHOD(IoSeq,each)990 IO_METHOD(IoSeq, each)
991 {
992 IoState *state = IOSTATE;
993 IoObject *result = IONIL(self);
994 IoMessage *doMessage = IoMessage_rawArgAt_(m, 0);
995 size_t i;
996
997 IoState_pushRetainPool(state);
998
999 for (i = 0; i < UArray_size(DATA(self)); i ++)
1000 {
1001 IoState_clearTopPool(IOSTATE);
1002
1003 if (UArray_isFloatType(DATA(self)))
1004 {
1005 result = IoMessage_locals_performOn_(doMessage, locals, IONUMBER(UArray_doubleAt_(DATA(self), i)));
1006 }
1007 else
1008 {
1009 result = IoMessage_locals_performOn_(doMessage, locals, IONUMBER(UArray_longAt_(DATA(self), i)));
1010 }
1011
1012 if (IoState_handleStatus(IOSTATE))
1013 {
1014 goto done;
1015 }
1016 }
1017
1018 done:
1019 IoState_popRetainPoolExceptFor_(state, result);
1020 return result;
1021 }
1022
1023
IO_METHOD(IoSeq,foreach)1024 IO_METHOD(IoSeq, foreach)
1025 {
1026 /*doc Sequence foreach(optionalIndex, value, message)
1027 For each element, set index to the index of the
1028 element and value to the element value and execute message.
1029 Example:
1030 <pre>
1031 aSequence foreach(i, v, writeln("value at index ", i, " is ", v))
1032 aSequence foreach(v, writeln("value ", v))
1033 </pre>
1034 */
1035
1036 IoObject *result = IONIL(self);
1037 IoMessage *doMessage;
1038
1039 IoSymbol *indexSlotName;
1040 IoSymbol *characterSlotName;
1041
1042 size_t i;
1043
1044 if (IoMessage_argCount(m) == 1)
1045 {
1046 return IoSeq_each(self, locals, m);
1047 }
1048
1049 IoMessage_foreachArgs(m, self, &indexSlotName, &characterSlotName, &doMessage);
1050
1051 IoState_pushRetainPool(IOSTATE);
1052
1053 for (i = 0; i < UArray_size(DATA(self)); i ++)
1054 {
1055 IoState_clearTopPool(IOSTATE);
1056
1057 if (indexSlotName)
1058 {
1059 IoObject_setSlot_to_(locals, indexSlotName, IONUMBER(i));
1060 }
1061
1062 if(UArray_isFloatType(DATA(self)))
1063 {
1064 IoObject_setSlot_to_(locals, characterSlotName, IONUMBER(UArray_doubleAt_(DATA(self), i)));
1065 }
1066 else
1067 {
1068 IoObject_setSlot_to_(locals, characterSlotName, IONUMBER(UArray_longAt_(DATA(self), i)));
1069 }
1070 result = IoMessage_locals_performOn_(doMessage, locals, locals);
1071
1072 if (IoState_handleStatus(IOSTATE))
1073 {
1074 goto done;
1075 }
1076 }
1077 done:
1078 IoState_popRetainPoolExceptFor_(IOSTATE, result);
1079 return result;
1080 }
1081
IO_METHOD(IoSeq,asMessage)1082 IO_METHOD(IoSeq, asMessage)
1083 {
1084 /*doc Sequence asMessage(optionalLabel)
1085 Returns the compiled message object for the string.
1086 */
1087
1088 IoSymbol *label;
1089
1090 if (IoMessage_argCount(m) >= 1)
1091 label = IoMessage_locals_symbolArgAt_(m, locals, 0);
1092 else
1093 label = IOSYMBOL("[asMessage]");
1094
1095 return IoMessage_newFromText_labelSymbol_(IOSTATE, CSTRING(self), label);
1096 }
1097
1098 /*doc Sequence ..(aSequence)
1099 Returns a copy of the receiver with aSequence appended to it.
1100 */
1101
IO_METHOD(IoSeq,cloneAppendSeq)1102 IO_METHOD(IoSeq, cloneAppendSeq)
1103 {
1104 IoObject *other = IoMessage_locals_valueArgAt_(m, locals, 0);
1105 UArray *ba;
1106
1107 if (ISNUMBER(other))
1108 {
1109 other = IoNumber_justAsString((IoNumber *)other, (IoObject *)locals, m);
1110 }
1111
1112 if (!ISSEQ(other))
1113 {
1114 IoState_error_(IOSTATE, m, "argument 0 to method '%s' must be a number or string, not a '%s'",
1115 CSTRING(IoMessage_name(m)),
1116 IoObject_name(other));
1117 }
1118
1119 if (UArray_size(DATA(other)) == 0)
1120 {
1121 return self;
1122 }
1123
1124 ba = UArray_clone(DATA(self));
1125 UArray_append_(ba, DATA(other));
1126 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1127 }
1128
1129
IO_METHOD(IoSeq,asMutable)1130 IO_METHOD(IoSeq, asMutable)
1131 {
1132 /*doc Sequence asMutable
1133 Returns a mutable copy of the receiver.
1134 */
1135
1136 return IoSeq_rawMutableCopy(self);
1137 }
1138
1139 /* --- case ------------------------------------------------ */
1140
IO_METHOD(IoSeq,asUppercase)1141 IO_METHOD(IoSeq, asUppercase)
1142 {
1143 /*doc Sequence asUppercase
1144 Returns a symbol containing the reveiver made uppercase.
1145 */
1146
1147 UArray *ba = UArray_clone(DATA(self));
1148 UArray_toupper(ba);
1149 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1150 }
1151
IO_METHOD(IoSeq,asLowercase)1152 IO_METHOD(IoSeq, asLowercase)
1153 {
1154 /*doc Sequence asLowercase
1155 Returns a symbol containing the reveiver made lowercase.
1156 */
1157
1158 UArray *ba = UArray_clone(DATA(self));
1159 UArray_tolower(ba);
1160 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1161 }
1162
1163 /* --- path ------------------------------------------------ */
1164
1165
IO_METHOD(IoSeq,lastPathComponent)1166 IO_METHOD(IoSeq, lastPathComponent)
1167 {
1168 /*doc Sequence lastPathComponent
1169 Returns a string containing the receiver clipped up
1170 to the last path separator.
1171 */
1172
1173 UArray *ba = UArray_lastPathComponent(DATA(self));
1174 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1175 }
1176
IO_METHOD(IoSeq,pathExtension)1177 IO_METHOD(IoSeq, pathExtension)
1178 {
1179 /*doc Sequence pathExtension
1180 Returns a string containing the receiver clipped up to the last period.
1181 */
1182
1183 UArray *path = UArray_pathExtension(DATA(self));
1184 return IoState_symbolWithUArray_copy_(IOSTATE, path, 0);
1185 }
1186
IO_METHOD(IoSeq,fileName)1187 IO_METHOD(IoSeq, fileName)
1188 {
1189 /*doc Sequence fileName
1190 Returns the last path component sans the path extension.
1191 */
1192
1193 UArray *path = UArray_fileName(DATA(self));
1194 return IoState_symbolWithUArray_copy_(IOSTATE, path, 0);
1195 }
1196
IO_METHOD(IoSeq,cloneAppendPath)1197 IO_METHOD(IoSeq, cloneAppendPath)
1198 {
1199 /*doc Sequence cloneAppendPath(aSequence)
1200 Appends argument to a copy the receiver such that there is one
1201 and only one path separator between the two and returns the result.
1202 */
1203
1204 IoSeq *component = IoMessage_locals_seqArgAt_(m, locals, 0);
1205 UArray *ba = UArray_clone(DATA(self));
1206 UArray_appendPath_(ba, DATA(component));
1207 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1208 }
1209
IO_METHOD(IoSeq,pathComponent)1210 IO_METHOD(IoSeq, pathComponent)
1211 {
1212 /*doc Sequence pathComponent
1213 Returns a slice of the receiver before the last path separator as a symbol.
1214 */
1215
1216 UArray *ba = UArray_clone(DATA(self));
1217 UArray_removeLastPathComponent(ba);
1218 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1219 }
1220
IO_METHOD(IoSeq,asOSPath)1221 IO_METHOD(IoSeq, asOSPath)
1222 {
1223 //doc Sequence asOSPath Returns a OS style path for an Io style path.
1224 return IoSeq_newSymbolWithUArray_copy_(IOSTATE, UArray_asOSPath(IoSeq_rawUArray(self)), 0);
1225 }
1226
IO_METHOD(IoSeq,asIoPath)1227 IO_METHOD(IoSeq, asIoPath)
1228 {
1229 //doc Sequence asIoPath Returns a Io style path for an OS style path.
1230 return IoSeq_newSymbolWithUArray_copy_(IOSTATE, UArray_asUnixPath(IoSeq_rawUArray(self)), 0);
1231 }
1232
1233 // occurrences
1234
IO_METHOD(IoSeq,beforeSeq)1235 IO_METHOD(IoSeq, beforeSeq)
1236 {
1237 /*doc Sequence beforeSeq(aSequence)
1238 Returns the slice of the receiver (as a Symbol) before
1239 aSequence or self if aSequence is not found.
1240 */
1241
1242 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1243 long pos = UArray_find_(DATA(self), DATA(other));
1244
1245 if (pos != -1)
1246 {
1247 UArray *ba = UArray_slice(DATA(self), 0, pos);
1248
1249 if (ISSYMBOL(self))
1250 {
1251 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1252 }
1253 else
1254 {
1255 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1256 }
1257 }
1258
1259 if (ISSYMBOL(self))
1260 {
1261 return self;
1262 }
1263
1264 return IOCLONE(self);
1265 }
1266
IO_METHOD(IoSeq,afterSeq)1267 IO_METHOD(IoSeq, afterSeq)
1268 {
1269 /*doc Sequence afterSeq(aSequence)
1270 Returns the slice of the receiver (as a Symbol) after aSequence or
1271 nil if aSequence is not found. If aSequence is empty, the receiver
1272 (or a copy of the receiver if it is mutable) is returned.
1273 */
1274
1275 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1276 long pos = UArray_find_(DATA(self), DATA(other));
1277
1278 if (pos != -1)
1279 {
1280 UArray *ba = UArray_slice(DATA(self), pos + UArray_size(DATA(other)), UArray_size(DATA(self)));
1281
1282 if (ISSYMBOL(self))
1283 {
1284 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1285 }
1286 else
1287 {
1288 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1289 }
1290 }
1291
1292 return IONIL(self);
1293 }
1294
IO_METHOD(IoSeq,asCapitalized)1295 IO_METHOD(IoSeq, asCapitalized)
1296 {
1297 /*doc Sequence asCapitalized
1298 Returns a copy of the receiver with the first charater made uppercase.
1299 */
1300
1301 /* need to fix for multi-byte characters */
1302
1303 int firstChar = (int)UArray_firstLong(DATA(self));
1304 int upperChar = toupper(firstChar);
1305
1306 if (ISSYMBOL(self) && (firstChar == upperChar))
1307 {
1308 return self;
1309 }
1310 else
1311 {
1312 UArray *ba = UArray_clone(DATA(self));
1313 UArray_at_putLong_(ba, 0, upperChar);
1314
1315 if (ISSYMBOL(self))
1316 {
1317 return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
1318 }
1319
1320 return IoSeq_newWithUArray_copy_(IOSTATE, ba, 0);
1321 }
1322 }
1323
IO_METHOD(IoSeq,occurrencesOfSeq)1324 IO_METHOD(IoSeq, occurrencesOfSeq)
1325 {
1326 /*doc Sequence occurrencesOfSeq(aSeq)
1327 Returns count of aSeq in the receiver.
1328 */
1329
1330 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1331 size_t count = UArray_count_(DATA(self), DATA(other));
1332 return IONUMBER(count);
1333 }
1334
IO_METHOD(IoSeq,asBase64)1335 IO_METHOD(IoSeq, asBase64)
1336 {
1337 /*doc Sequence asBase64(optionalCharactersPerLine)
1338 Returns an immutable, base64 encoded (according to RFC 1421) version of self.
1339 optionalCharactersPerLine describes the number of characters between line breaks and defaults to 0.
1340 */
1341 int charsPerLine = 0;
1342
1343 if (IoMessage_argCount(m) > 0)
1344 {
1345 charsPerLine = IoMessage_locals_intArgAt_(m, locals, 0);
1346 }
1347
1348 return IoSeq_newWithUArray_copy_(IOSTATE, UArray_asBase64(IoSeq_rawUArray(self), charsPerLine), 0);
1349 }
1350
IO_METHOD(IoSeq,fromBase64)1351 IO_METHOD(IoSeq, fromBase64)
1352 {
1353 /*doc Sequence fromBase64
1354 Returns an immutable, base64 decoded (according to RFC 1421) version of self.
1355 */
1356
1357 return IoSeq_newWithUArray_copy_(IOSTATE, UArray_fromBase64(IoSeq_rawUArray(self)), 0);
1358 }
1359
IO_METHOD(IoSeq,interpolate)1360 IO_METHOD(IoSeq, interpolate)
1361 {
1362 /*doc Sequence interpolate(ctx)
1363 Returns immutable copy of self with interpolateInPlace(ctx) passed to the copy.
1364 */
1365
1366 IoSeq *s = IoSeq_newWithUArray_copy_(IOSTATE, IoSeq_rawUArray(self), 1);
1367 IoSeq_interpolateInPlace(s, locals, m);
1368 return IoSeq_rawAsSymbol(s);
1369 }
1370
IO_METHOD(IoSeq,distanceTo)1371 IO_METHOD(IoSeq, distanceTo)
1372 {
1373 /*doc Sequence distanceTo(aSeq)
1374 Returns a number with the square root of the sum of the square
1375 of the differences of the items between the sequences.
1376 */
1377
1378 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1379 double d;
1380
1381 d = UArray_distanceTo_(DATA(self), DATA(other));
1382 return IONUMBER(d);
1383 }
1384
IO_METHOD(IoSeq,greaterThan_)1385 IO_METHOD(IoSeq, greaterThan_)
1386 {
1387 /*doc Sequence greaterThan(aSeq)
1388 Returns true if the receiver is greater than aSeq, false otherwise.
1389 */
1390
1391 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1392 return IOBOOL(self, UArray_greaterThan_(DATA(self), DATA(other)));
1393 }
1394
IO_METHOD(IoSeq,lessThan_)1395 IO_METHOD(IoSeq, lessThan_)
1396 {
1397 /*doc Sequence lessThan(aSeq)
1398 Returns true if the receiver is less than aSeq, false otherwise.
1399 */
1400
1401 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1402 return IOBOOL(self, UArray_lessThan_(DATA(self), DATA(other)));
1403 }
1404
IO_METHOD(IoSeq,greaterThanOrEqualTo_)1405 IO_METHOD(IoSeq, greaterThanOrEqualTo_)
1406 {
1407 /*doc Sequence greaterThanOrEqualTo(aSeq)
1408 Returns true if the receiver is greater than or equal to aSeq, false otherwise.
1409 */
1410
1411 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1412 return IOBOOL(self, UArray_greaterThanOrEqualTo_(DATA(self), DATA(other)));
1413 }
1414
IO_METHOD(IoSeq,lessThanOrEqualTo_)1415 IO_METHOD(IoSeq, lessThanOrEqualTo_)
1416 {
1417 /*doc Sequence lessThanOrEqualTo(aSeq)
1418 Returns true if the receiver is less than or equal to aSeq, false otherwise.
1419 */
1420
1421 IoSeq *other = IoMessage_locals_seqArgAt_(m, locals, 0);
1422 return IOBOOL(self, UArray_lessThanOrEqualTo_(DATA(self), DATA(other)));
1423 }
1424
1425 // -----------------------------------------------------------
1426
1427 #define ASSTRUCT(type) if (!strcmp(mt, #type)) \
1428 { \
1429 int typeSize = sizeof(type ## _t); \
1430 IOASSERT(offset + typeSize <= size, "not enough data for struct"); \
1431 v = IONUMBER(*(type ## _t *)(data + offset)); \
1432 offset += typeSize; \
1433 }
1434
IO_METHOD(IoSeq,asStruct)1435 IO_METHOD(IoSeq, asStruct)
1436 {
1437 /*doc Sequence asStruct(memberList)
1438 For a sequence that contains the data for a raw memory data structure (as used in C),
1439 this method can be used to extract its members into an Object. The memberList argument
1440 specifies the layout of the datastructure. Its form is:
1441 <p>
1442 list(memberType1, memberName1, memberType2, memberName2, ...)
1443 <p>
1444 Member types include:
1445 <pre>
1446 int8, int16, int32, int64
1447 uint8, uint16, uint32, uint64
1448 float32, float64
1449 </pre>
1450 Example:
1451 <pre>
1452 pointObject := structPointSeq asStruct(list("float32", "x", "float32", "y"))
1453 </pre>
1454 The output pointObject would contain x and y slots with Number objects.
1455 */
1456
1457 IoObject *st = IoObject_new(IOSTATE);
1458 const unsigned char *data = UArray_bytes(DATA(self));
1459 size_t size = UArray_sizeInBytes(DATA(self));
1460 size_t offset = 0;
1461 List *members = IoList_rawList(IoMessage_locals_listArgAt_(m, locals, 0));
1462 int memberIndex;
1463
1464 IOASSERT(List_size(members) % 2 == 0, "members list must be even number");
1465
1466 for (memberIndex = 0; memberIndex < List_size(members) / 2 && offset < size; memberIndex ++)
1467 {
1468 IoSeq *memberType = List_at_(members, memberIndex*2);
1469 IoSeq *memberName = List_at_(members, memberIndex*2 + 1);
1470 char *mt;
1471 IoObject *v = NULL;
1472
1473 IOASSERT(ISSEQ(memberType), "memberTypes must be strings");
1474 IOASSERT(ISSEQ(memberName), "memberNames must be strings");
1475
1476 mt = CSTRING(memberType);
1477
1478 ASSTRUCT(int8);
1479 ASSTRUCT(uint8);
1480 ASSTRUCT(int16);
1481 ASSTRUCT(uint16);
1482 ASSTRUCT(int32);
1483 ASSTRUCT(uint32);
1484 ASSTRUCT(int64);
1485 ASSTRUCT(uint64);
1486 ASSTRUCT(float32);
1487 ASSTRUCT(float64);
1488
1489 IoObject_setSlot_to_(st, memberName, v);
1490 }
1491
1492 return st;
1493 }
1494
1495 #define WITHSTRUCT(type) if (!strcmp(mt, #type)) \
1496 { \
1497 int typeSize = sizeof(type ## _t); \
1498 *(type ## _t *)(data + offset) = CNUMBER(memberValue); \
1499 offset += typeSize; \
1500 continue; \
1501 }
1502
IO_METHOD(IoSeq,withStruct)1503 IO_METHOD(IoSeq, withStruct)
1504 {
1505 /*doc Sequence withStruct(memberList)
1506 This method is useful for producing a Sequence containing a raw datastructure with
1507 the specified types and values. The memberList format is:
1508 <p>
1509 list(memberType1, memberName1, memberType2, memberName2, ...)
1510 <p>
1511 Member types include:
1512 <pre>
1513 int8, int16, int32, int64
1514 uint8, uint16, uint32, uint64
1515 float32, float64
1516 </pre>
1517 Example:
1518 <pre>
1519 pointStructSeq := Sequence withStruct(list("float32", 1.2, "float32", 3.5))
1520 </pre>
1521 The output pointStructSeq would contain 2 raw 32 bit floats.
1522 */
1523
1524 List *members = IoList_rawList(IoMessage_locals_listArgAt_(m, locals, 0));
1525 int memberIndex;
1526 size_t maxSize = List_size(members) * 8;
1527 IoSeq *s = IoSeq_newWithData_length_(IOSTATE, (unsigned char *)malloc(maxSize), maxSize);
1528 unsigned char *data = IoSeq_rawBytes(s);
1529 size_t offset = 0;
1530
1531 IOASSERT(List_size(members) % 2 == 0, "members list must be even number");
1532
1533 for (memberIndex = 0; memberIndex < List_size(members) / 2 && offset < maxSize; memberIndex ++)
1534 {
1535 IoSeq *memberType = List_at_(members, memberIndex*2);
1536 IoSeq *memberValue = List_at_(members, memberIndex*2 + 1);
1537 char *mt;
1538
1539 IOASSERT(ISSEQ(memberType), "memberTypes must be strings");
1540 IOASSERT(ISNUMBER(memberValue), "memberValues must be strings");
1541
1542 mt = CSTRING(memberType);
1543
1544 WITHSTRUCT(int8);
1545 WITHSTRUCT(uint8);
1546 WITHSTRUCT(int16);
1547 WITHSTRUCT(uint16);
1548 WITHSTRUCT(int32);
1549 WITHSTRUCT(uint32);
1550 WITHSTRUCT(int64);
1551 WITHSTRUCT(uint64);
1552 WITHSTRUCT(float32);
1553 WITHSTRUCT(float64);
1554 }
1555
1556 IoSeq_rawSetSize_(s, offset);
1557
1558 return s;
1559 }
1560
1561 // ------------------
1562
1563 /* Converts a hex character to its integer value */
from_hex(char ch)1564 static char from_hex(char ch)
1565 {
1566 return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
1567 }
1568
1569 /* Converts an integer value to its hex character*/
to_hex(char code)1570 static char to_hex(char code)
1571 {
1572 static char hex[] = "0123456789ABCDEF";
1573 return hex[code & 15];
1574 }
1575
1576
1577 /* Returns a url-encoded version of str */
1578 /* IMPORTANT: be sure to free() the returned string after use */
url_encode(const char * str,int isPercentEncoded)1579 static char *url_encode(const char *str, int isPercentEncoded)
1580 {
1581 const char *pstr = str;
1582 char *buf = (char *)malloc(strlen(str) * 3 + 1);
1583 char *pbuf = buf;
1584
1585 while (*pstr)
1586 {
1587 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
1588 {
1589 *pbuf++ = *pstr;
1590 }
1591 else if (!isPercentEncoded && *pstr == ' ')
1592 {
1593 *pbuf++ = '+';
1594 }
1595 else
1596 {
1597 *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
1598 }
1599
1600 pstr++;
1601 }
1602
1603 *pbuf = '\0';
1604 return buf;
1605 }
1606
1607 /* Returns a url-decoded version of str */
1608 /* IMPORTANT: be sure to free() the returned string after use */
url_decode(const char * str,int isPercentEncoded)1609 static char *url_decode(const char *str, int isPercentEncoded)
1610 {
1611 const char *pstr = str;
1612 char *buf = (char *)malloc(strlen(str) + 1);
1613 char *pbuf = buf;
1614
1615 while (*pstr)
1616 {
1617 if (*pstr == '%')
1618 {
1619 if (pstr[1] && pstr[2])
1620 {
1621 *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
1622 pstr += 2;
1623 }
1624 }
1625 else if (!isPercentEncoded && *pstr == '+')
1626 {
1627 *pbuf++ = ' ';
1628 }
1629 else
1630 {
1631 *pbuf++ = *pstr;
1632 }
1633 pstr++;
1634 }
1635
1636 *pbuf = '\0';
1637 return buf;
1638 }
1639
IO_METHOD(IoSeq,percentEncoded)1640 IO_METHOD(IoSeq, percentEncoded)
1641 {
1642 /*doc Sequence percentEncoded
1643 Returns percent encoded version of receiver.
1644 */
1645 char *s = url_encode((const char *)UArray_bytes(DATA(self)), 1);
1646 IoObject *result = IOSYMBOL(s);
1647 free(s);
1648 return result;
1649 }
1650
IO_METHOD(IoSeq,percentDecoded)1651 IO_METHOD(IoSeq, percentDecoded)
1652 {
1653 /*doc Sequence percentDecoded
1654 Returns percent decoded version of receiver.
1655 */
1656 char *s = url_decode((const char *)UArray_bytes(DATA(self)), 1);
1657 IoObject *result = IOSYMBOL(s);
1658 free(s);
1659 return result;
1660 }
1661
1662 // ----------------------------
1663
IO_METHOD(IoSeq,urlEncoded)1664 IO_METHOD(IoSeq, urlEncoded)
1665 {
1666 /*doc Sequence urlEncoded
1667 Returns url encoded version of receiver.
1668 */
1669 char *s = url_encode((const char *)UArray_bytes(DATA(self)), 0);
1670 IoObject *result = IOSYMBOL(s);
1671 free(s);
1672 return result;
1673 }
1674
IO_METHOD(IoSeq,urlDecoded)1675 IO_METHOD(IoSeq, urlDecoded)
1676 {
1677 /*doc Sequence urlDecoded
1678 Returns url decoded version of receiver.
1679 */
1680 char *s = url_decode((const char *)UArray_bytes(DATA(self)), 0);
1681 IoObject *result = IOSYMBOL(s);
1682 free(s);
1683 return result;
1684 }
1685
1686 // -------------------------
1687
1688
IO_METHOD(IoSeq,pack)1689 IO_METHOD(IoSeq, pack)
1690 {
1691 /*doc Sequence pack(format, value1, ...)
1692
1693 Returns a new Sequence with the values packed in.
1694
1695 Codes:
1696
1697 *: (one at the beginning of the format string) declare format string as BigEndian
1698 B: unsigned byte
1699 b: byte
1700 C: unsigned char
1701 c: char
1702 H: unsigned short
1703 h: short
1704 I: unsigned int
1705 i: int
1706 L: unsigned long
1707 l: long
1708 f: float
1709 F: double
1710 s: string
1711
1712 A '*' at the begging of the format string indicates native types are to be treated as Big Endiand.
1713
1714 A number preceding a code declares an array of that type.
1715
1716 In the case of 's', the preceding number indicates the size of the string to be packed.
1717 If the string passed is shorter than size, 0 padding will be used to fill to size. If the
1718 string passed is longer than size, only size chars will be packed.
1719
1720 The difference between b/B and c/C is in the values passed to pack. For b/B pack expects a number.
1721 For c/C pack expects a one-char-string (this is the same as '1s' or 's')
1722
1723 Examples:
1724
1725 s := Sequence pack("IC5s", 100, "a", "hello")
1726 s := Sequence pack("5c", "h", "e", "l", "l", "o")
1727 s := Sequence pack("I", 0x01020304)
1728 s := Sequence pack("*I", 0x01020304)
1729
1730 */
1731
1732 char *strFmt = IoMessage_locals_cStringArgAt_(m, locals, 0);
1733 size_t strFmtLen = strlen(strFmt);
1734 int argCount = IoMessage_argCount(m);
1735 int isBigEndian = 0;
1736 int doBigEndian = 0;
1737 size_t i = 0;
1738 int argIdx = 0;
1739 size_t count = 0;
1740
1741 char *from = NULL;
1742 size_t size = 0;
1743 size_t padding = 0;
1744 char val[16];
1745 UArray *ua = UArray_new();
1746
1747 memset(val, 0x0, 16);
1748
1749 UArray_setItemType_(ua, CTYPE_uint8_t);
1750 UArray_setEncoding_(ua, CENCODING_NUMBER);
1751
1752 if(strFmt[0] == '*') i = doBigEndian = isBigEndian = 1;
1753
1754 for(argIdx = 1 ; i < strFmtLen && argIdx < argCount ; i ++)
1755 {
1756 if(isdigit(strFmt[i]))
1757 {
1758 count = (count * 10) + (strFmt[i] - 0x30);
1759 continue;
1760 }
1761
1762 count = count > 1 ? count : 1;
1763
1764 doBigEndian = isBigEndian;
1765
1766 for( ; count > 0 ; count --, argIdx ++)
1767 {
1768 from = val;
1769 padding = 0;
1770 size = 0;
1771
1772 switch(strFmt[i])
1773 {
1774 case 'B': //unsigned byte
1775 case 'b': //byte
1776 val[0] = IoMessage_locals_intArgAt_(m, locals, argIdx);
1777 size = sizeof(char);
1778 break;
1779
1780 case 'C': //unsigned char
1781 case 'c': //char
1782 val[0] = IoMessage_locals_cStringArgAt_(m, locals, argIdx)[0];
1783 size = sizeof(char);
1784 break;
1785
1786 case 'H': //unsigned short
1787 case 'h': //short
1788 *((short *)val) = (short)IoMessage_locals_intArgAt_(m, locals, argIdx);
1789 size = sizeof(short);
1790 break;
1791
1792 case 'I': //unsigned int
1793 case 'i': //int
1794 *((int *)val) = IoMessage_locals_intArgAt_(m, locals, argIdx);
1795 size = sizeof(int);
1796 break;
1797
1798 case 'L': //unsigned long
1799 case 'l': //long
1800 *((long *)val) = IoMessage_locals_intArgAt_(m, locals, argIdx);
1801 size = sizeof(long);
1802 break;
1803
1804 case 'f': //float
1805 *((float *)val) = IoMessage_locals_floatArgAt_(m, locals, argIdx);
1806 size = sizeof(float);
1807 break;
1808
1809 case 'F': //double
1810 *((double *)val) = IoMessage_locals_doubleArgAt_(m, locals, argIdx);
1811 size = sizeof(double);
1812 break;
1813
1814 case 's': //string
1815 from = IoMessage_locals_cStringArgAt_(m, locals, argIdx);
1816 size = strlen(from);
1817 if(count > size)
1818 padding = count - size;
1819 else
1820 size = count;
1821 doBigEndian = 0;
1822 count = 1; //finish processing
1823 break;
1824 }
1825
1826 {
1827 long inc = doBigEndian ? -1 : 1;
1828 long pos = doBigEndian ? size - 1 : 0;
1829 int j = 0;
1830
1831 for(j = 0 ; j < size ; j ++, pos += inc)
1832 {
1833 UArray_appendLong_(ua, from[pos]);
1834 }
1835
1836 for(j = 0 ; j < padding ; j ++)
1837 {
1838 UArray_appendLong_(ua, 0);
1839 }
1840 }
1841 }
1842 }
1843
1844 return IoSeq_newWithUArray_copy_(IOSTATE, ua, 0);
1845 }
1846
1847
1848 /*#define SEQ_UNPACK_VALUE_ASSIGN_LOOP(code, type, dest, toObj) \
1849 case code: \
1850 { \
1851 int inc = isBigEndian ? -1 : 1; \
1852 int pos = isBigEndian ? seqPos + sizeof(type) - 1 : seqPos; \
1853 int j; \
1854 \
1855 for(j = 0 ; j < sizeof(type) ; j ++, pos += inc) \
1856 dest[j] = UArray_longAt_(selfUArray, pos); \
1857 \
1858 toObj = IONUMBER(*((type *)dest)); \
1859 seqPos += sizeof(type); \
1860 } \
1861 break;*/
1862
1863 #define SEQ_UNPACK_VALUE_ASSIGN_LOOP(code, type, dest, toObj) \
1864 case code: \
1865 { \
1866 size_t inc = isBigEndian ? -1 : 1; \
1867 size_t pos = isBigEndian ? seqPos + sizeof(type) - 1 : seqPos; \
1868 size_t j; \
1869 \
1870 for(j = 0 ; j < sizeof(type) ; j ++, pos += inc) \
1871 dest[j] = selfUArray[pos]; \
1872 \
1873 toObj = IONUMBER(*((type *)dest)); \
1874 seqPos += sizeof(type); \
1875 } \
1876 break;
1877
1878
IO_METHOD(IoSeq,unpack)1879 IO_METHOD(IoSeq, unpack)
1880 {
1881 /*doc Sequence unpack(optionalStartPosition, format)
1882
1883 Unpacks self into a list using the format passed in. See Sequence pack.
1884
1885 Returns a List.
1886
1887 Examples:
1888
1889 s := Sequence pack("IC5s", 100, "a", "hello")
1890 l := s unpack("IC5s")
1891
1892 s := Sequence pack("5c", "h", "e", "l", "l", "o")
1893 l := s unpack("5c")
1894
1895 s := Sequence pack("I", 0x01020304)
1896 l := s unpack("I")
1897
1898 s := Sequence pack("*I", 0x01020304)
1899 l := s unpack("*I")
1900
1901 l := "hello" unpack("5c")
1902 */
1903
1904 char *strFmt = NULL;
1905 size_t strFmtLen = 0;
1906 int isBigEndian = 0;
1907 size_t i = 0;
1908 size_t count = 0;
1909 size_t seqPos = 0;
1910 char val[16];
1911
1912 IoList *values = IoList_new(IOSTATE);
1913 //UArray *selfUArray = DATA(self);
1914 char *selfUArray = (char *)DATA(self)->data;
1915 size_t selfUArraySize = UArray_size(DATA(self));
1916
1917 if(IoMessage_argCount(m) == 1)
1918 {
1919 strFmt = IoMessage_locals_cStringArgAt_(m, locals, 0);
1920 }
1921 else
1922 {
1923 seqPos = IoMessage_locals_intArgAt_(m, locals, 0);
1924 strFmt = IoMessage_locals_cStringArgAt_(m, locals, 1);
1925 }
1926
1927 strFmtLen = strlen(strFmt);
1928
1929 if(strFmt[0] == '*') i = isBigEndian = 1;
1930
1931 for(count = 0 ; i < strFmtLen && seqPos < selfUArraySize; i ++)
1932 {
1933 if(isdigit(strFmt[i]))
1934 {
1935 count = (count * 10) + (strFmt[i] - 0x30);
1936 continue;
1937 }
1938
1939 count = count > 1 ? count : 1;
1940
1941 for( ; count > 0 ; count --)
1942 {
1943 IoObject *v;
1944
1945 switch(strFmt[i])
1946 {
1947 SEQ_UNPACK_VALUE_ASSIGN_LOOP('b', char, val, v)
1948 SEQ_UNPACK_VALUE_ASSIGN_LOOP('B', unsigned char, val, v)
1949 SEQ_UNPACK_VALUE_ASSIGN_LOOP('c', char, val, v)
1950 SEQ_UNPACK_VALUE_ASSIGN_LOOP('C', unsigned char, val, v)
1951 SEQ_UNPACK_VALUE_ASSIGN_LOOP('h', short, val, v)
1952 SEQ_UNPACK_VALUE_ASSIGN_LOOP('H', unsigned short, val, v)
1953 SEQ_UNPACK_VALUE_ASSIGN_LOOP('i', int, val, v)
1954 SEQ_UNPACK_VALUE_ASSIGN_LOOP('I', unsigned int, val, v)
1955 SEQ_UNPACK_VALUE_ASSIGN_LOOP('l', long, val, v)
1956 SEQ_UNPACK_VALUE_ASSIGN_LOOP('L', unsigned long, val, v)
1957 SEQ_UNPACK_VALUE_ASSIGN_LOOP('f', float, val, v)
1958 SEQ_UNPACK_VALUE_ASSIGN_LOOP('F', double, val, v)
1959
1960 case 's': //string
1961 {
1962 UArray *ua = UArray_new();
1963 char *uap = (char *)ua->data;
1964 UArray_setItemType_(ua, CTYPE_uint8_t);
1965 UArray_setEncoding_(ua, CENCODING_ASCII);
1966
1967 if(count == 1) {
1968 //while(c = UArray_longAt_(selfUArray, seqPos ++)) {
1969 // UArray_appendLong_(ua, c);
1970 //}
1971 count = strlen(&selfUArray[seqPos]);
1972 UArray_setSize_(ua, count);
1973 strcpy(uap, &selfUArray[seqPos]);
1974 }
1975 else {
1976 //for( ; count > 0 ; count --) {
1977 // UArray_appendLong_(ua, UArray_longAt_(selfUArray, seqPos ++));
1978 //}
1979 UArray_setSize_(ua, count);
1980 memcpy(uap, &selfUArray[seqPos], count);
1981 }
1982 seqPos += count;
1983 count = 1;
1984 v = IoSeq_newWithUArray_copy_(IOSTATE, ua, 0);
1985 break;
1986 }
1987 }
1988
1989 IoList_rawAppend_(values, v);
1990 }
1991 }
1992
1993 return values;
1994 }
1995
1996 // -------------------------
1997
IoSeq_addImmutableMethods(IoSeq * self)1998 void IoSeq_addImmutableMethods(IoSeq *self)
1999 {
2000 IoMethodTable methodTable[] = {
2001 {"itemType", IoSeq_itemType},
2002 {"itemSize", IoSeq_itemSize},
2003 {"encoding", IoSeq_encoding},
2004 {"asUTF8", IoSeq_asUTF8},
2005 {"asUCS2", IoSeq_asUCS2},
2006 {"asUCS4", IoSeq_asUCS4},
2007 {"asFixedSizeType", IoSeq_asFixedSizeType},
2008
2009 {"asBinaryNumber", IoSeq_asBinaryNumber},
2010 {"asBinaryUnsignedInteger", IoSeq_asBinaryUnsignedInteger},
2011 {"asBinarySignedInteger", IoSeq_asBinaryUnsignedInteger},
2012 {"isSymbol", IoSeq_isSymbol},
2013 {"isMutable", IoSeq_isMutable},
2014 {"asSymbol", IoSeq_asSymbol},
2015 {"asString", IoSeq_asSymbol},
2016 {"asNumber", IoSeq_asNumber},
2017 {"asList", IoSeq_asList},
2018 {"whiteSpaceStrings", IoSeq_whiteSpaceStrings},
2019 {"print", IoSeq_print},
2020 {"linePrint", IoSeq_linePrint},
2021 {"parseJson", IoSeq_parseJson},
2022 {"size", IoSeq_size},
2023 {"sizeInBytes", IoSeq_sizeInBytes},
2024 {"isZero", IoSeq_isZero},
2025 {"isEmpty", IoSeq_isEmpty},
2026 {"at", IoSeq_at},
2027 {"exclusiveSlice", IoSeq_exclusiveSlice},
2028 {"exSlice", IoSeq_exclusiveSlice},
2029 {"inclusiveSlice", IoSeq_inclusiveSlice},
2030 {"inSlice", IoSeq_inclusiveSlice},
2031 {"between", IoSeq_between},
2032 {"betweenSeq", IoSeq_between},
2033 {"findSeqs", IoSeq_findSeqs},
2034 {"findSeq", IoSeq_findSeq},
2035 {"reverseFindSeq", IoSeq_reverseFindSeq},
2036 {"beginsWithSeq", IoSeq_beginsWithSeq},
2037 {"endsWithSeq", IoSeq_endsWithSeq},
2038 {"split", IoSeq_split},
2039 {"contains", IoSeq_contains},
2040 {"containsSeq", IoSeq_containsSeq},
2041 {"containsAnyCaseSeq", IoSeq_containsAnyCaseSeq},
2042 {"isLowercase", IoSeq_isLowercase},
2043 {"isUppercase", IoSeq_isUppercase},
2044 {"isEqualAnyCase", IoSeq_isEqualAnyCase},
2045 {"splitAt", IoSeq_splitAt},
2046 {"fromBase", IoSeq_fromBase},
2047 {"toBase", IoSeq_toBase},
2048 {"foreach", IoSeq_foreach},
2049 {"asMessage", IoSeq_asMessage},
2050 {"..", IoSeq_cloneAppendSeq},
2051 {"cloneAppendSeq", IoSeq_cloneAppendSeq},
2052 {"asMutable", IoSeq_asMutable},
2053 {"asBuffer", IoSeq_asMutable},
2054
2055 // paths
2056
2057 {"fileName", IoSeq_fileName},
2058 {"pathExtension", IoSeq_pathExtension},
2059 {"lastPathComponent", IoSeq_lastPathComponent},
2060 {"cloneAppendPath", IoSeq_cloneAppendPath},
2061 {"pathComponent", IoSeq_pathComponent},
2062 {"asOSPath", IoSeq_asOSPath},
2063 {"asIoPath", IoSeq_asIoPath},
2064
2065 {"afterSeq", IoSeq_afterSeq},
2066 {"beforeSeq", IoSeq_beforeSeq},
2067
2068 {"asCapitalized", IoSeq_asCapitalized},
2069 {"asUppercase", IoSeq_asUppercase},
2070 {"asLowercase", IoSeq_asLowercase},
2071 {"with", IoSeq_with},
2072 {"occurrencesOfSeq", IoSeq_occurrencesOfSeq},
2073 {"interpolate", IoSeq_interpolate},
2074 {"distanceTo", IoSeq_distanceTo},
2075
2076 {"asBase64", IoSeq_asBase64},
2077 {"fromBase64", IoSeq_fromBase64},
2078
2079 {">", IoSeq_greaterThan_},
2080 {"<", IoSeq_lessThan_},
2081 {">=", IoSeq_greaterThanOrEqualTo_},
2082 {"<=", IoSeq_lessThanOrEqualTo_},
2083
2084 {"asStruct", IoSeq_asStruct},
2085 {"withStruct", IoSeq_withStruct},
2086
2087 {"percentEncoded", IoSeq_percentEncoded},
2088 {"percentDecoded", IoSeq_percentDecoded},
2089
2090 {"urlEncoded", IoSeq_urlEncoded},
2091 {"urlDecoded", IoSeq_urlDecoded},
2092
2093 {"pack", IoSeq_pack},
2094 {"unpack", IoSeq_unpack},
2095
2096 {NULL, NULL},
2097 };
2098
2099 IoObject_addMethodTable_(self, methodTable);
2100 }
2101