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