rev 599 - in trunk: include/prothon pr/test src

SVN User <[email protected]> Fri, 11 Jun 2004 04:22:33 -0400
Newsgroups gmane.comp.lang.prothon.cvs
Message-ID <[email protected]>
Author: mark
Date: 2004-06-11 04:22:30 -0400 (Fri, 11 Jun 2004)
New Revision: 599

Modified:
   trunk/include/prothon/prothon.h
   trunk/pr/test/strmod.pr
   trunk/pr/test/test.pr
   trunk/src/builtins-string.c
Log:
changed all string methods except case changing, mod, and cmp to support 24-bits

Modified: trunk/include/prothon/prothon.h
===================================================================
--- trunk/include/prothon/prothon.h	2004-06-10 21:14:51 UTC (rev 598)
+++ trunk/include/prothon/prothon.h	2004-06-11 08:22:30 UTC (rev 599)
@@ -682,7 +682,7 @@
 #define NEW_STRINGN(string, n)  new_string_n_obj(ist, string, n)
 
 // NEW_STRING_CH3_OBJ: Create a new string object from a 24-bit char string of N chars long.
-obj_p new_string_ch3_obj(isp ist, ch3_p ch3p, data_size_t n);
+obj_p new_string_ch3_obj(isp ist, ch3_p ch3p, size_t n);
 #define NEW_STRING_CH3(ch3p, n)  new_string_ch3_obj(ist, ch3p, n)
 
 // SET_STRING_DATA: Change an existing object's data to string data

Modified: trunk/pr/test/strmod.pr
===================================================================
--- trunk/pr/test/strmod.pr	2004-06-10 21:14:51 UTC (rev 598)
+++ trunk/pr/test/strmod.pr	2004-06-11 08:22:30 UTC (rev 599)
@@ -92,7 +92,7 @@
 	failures = failures+1
 
 if "aaaaabaacaadaaaaabaacaad".find("aab",0) != 3:
-	print "split() failed!"
+	print "find() failed!"
 	failures = failures+1
 
 s = "%d" % 3333

Modified: trunk/pr/test/test.pr
===================================================================
--- trunk/pr/test/test.pr	2004-06-10 21:14:51 UTC (rev 598)
+++ trunk/pr/test/test.pr	2004-06-11 08:22:30 UTC (rev 599)
@@ -1,3 +1,3 @@
 #!/usr/bin/env prothon
 
-Bytes([9999999999999999999999999999999999999999999])
\ No newline at end of file
+print "abc" * (-1)
\ No newline at end of file

Modified: trunk/src/builtins-string.c
===================================================================
--- trunk/src/builtins-string.c	2004-06-10 21:14:51 UTC (rev 598)
+++ trunk/src/builtins-string.c	2004-06-11 08:22:30 UTC (rev 599)
@@ -67,10 +67,21 @@
 
 #include "pr_snprintf.h"
 
-#define is_String(objid)        (has_proto(ist, objid, String_OBJ))
+#define IS_STRING(objid) (has_proto(ist, objid, String_OBJ))
 
+#define IS_SPACE(ch3p)								       \
+	( ( (((ch3p)->b0)== ' ') || (((ch3p)->b0)=='\t') ||    \
+        (((ch3p)->b0)=='\r') || (((ch3p)->b0)=='\n') )  && \
+	  (((ch3p)->b1)==0)                                 && \
+	  (((ch3p)->b2)==0)  )
+
 #define ORD(ch3p)  (((u32_t)(ch3p)->b0)+((((u32_t)(ch3p)->b1)+(((u32_t)(ch3p)->b2)*256))*256))
 
+#define CH3EQ(ch3p1, ch3p2)					\
+	(	(((ch3p1)->b0)==((ch3p2)->b0)) &&	\
+		(((ch3p1)->b1)==((ch3p2)->b1)) &&	\
+		(((ch3p1)->b2)==((ch3p2)->b2))  )
+
 MODULE_DECLARE(String);
 MODULE_DECLARE(StringGen);
 
@@ -95,11 +106,11 @@
 }
 
 //********************************* new_string_ch3_obj **************************
-obj_p new_string_ch3_obj(isp ist, ch3_p str, data_size_t len) {
+obj_p new_string_ch3_obj(isp ist, ch3_p str, size_t len) {
 	obj_p obj;
 	if(!str) return NULL;
 	obj = NEW_OBJ(OBJ(STRING_PROTO));
-	pr2pr_strcpy(ist, obj, str, len);
+	pr2pr_strcpy(ist, obj, str, (data_size_t) len);
 	return obj;
 }
 
@@ -271,19 +282,18 @@
 	return NEW_STRING(dest_ptr);
 }
 
-//********************************* bin_strstr ********************************
-// strstr()-analog that works for strings that may contain nulls.
-// Totally dependent upon ASCII encoding; beware.
-static char* bin_strstr(char* haystack,size_t lhaystack, char* needle,size_t lneedle) {
-	char* lookfor = needle;
-	char* looking_at = haystack;
-	char* hs_end = haystack+lhaystack;
-	char* ndl_end = needle+lneedle;
+//********************************* ch3_strstr ********************************
+// strstr()-analog that works for ch3 strings
+static ch3_p ch3_strstr(ch3_p haystack, size_t lhaystack, ch3_p needle, size_t lneedle) {
+	ch3_p lookfor = needle;
+	ch3_p looking_at = haystack;
+	ch3_p hs_end = haystack + lhaystack;
+	ch3_p ndl_end = needle + lneedle;
 	while (looking_at < hs_end) {
-		if (*lookfor == *looking_at) {
+		if (CH3EQ(lookfor, looking_at)) {
 			// Matched a character.
 			++lookfor;
-			if (lookfor == ndl_end) {
+			if (CH3EQ(lookfor, ndl_end)) {
 				// Matched the whole string. It started lneedle-1
 				// characters before the character we're looking at
 				// now.
@@ -301,7 +311,7 @@
 		}
 		++looking_at;
 	}
-	return 0;
+	return NULL;
 }
 
 //********************************* STRING MODULE *****************************
@@ -405,7 +415,7 @@
 	BIN_CONTENT_CHK(String);
 	if (self == other)
 		return NEW_INT(0);
-	if (!is_String(other)) {
+	if (!IS_STRING(other)) {
 		raise_exception(ist, OBJ(TYPE_EXC), "Cannot compare a string and non-string");
 		return NULL;
 	}
@@ -415,41 +425,44 @@
 DEF(String, add_, FORM_RPARAM){
 	obj_p res, other = parms[1];
 	size_t slen, olen, tlen;
-	char* buf;
-
+	ch3_p buf;
 	BIN_CONTENT_CHK(String);
-	if (!is_String(other)) other = call_func0(ist, other, SYM(STR_));
+	if (!IS_STRING(other)) other = call_func0(ist, other, SYM(STR_));
 	slen = pr_strlen(self); olen = pr_strlen(other);
 	tlen = slen + olen;
-	buf = pr_malloc(tlen+1);
-	memcpy(buf,      pr2c_strptr(ist, self),  slen);
-	memcpy(buf+slen, pr2c_strptr(ist, other), olen);
-	buf[tlen] = 0;
-	res = NEW_STRINGN(buf, tlen);
+	buf = pr_malloc(tlen*3);
+	memcpy(buf,      pr_ch3ptr(self),  slen*3);
+	memcpy(buf+slen, pr_ch3ptr(other), olen*3);
+	res = NEW_STRING_CH3(buf, (int) tlen);
 	pr_free(buf);
 	return res;
 }
 
 DEF(String, mul_, FORM_RPARAM){
 	obj_p res;
-	size_t i, times, tlen, len = pr_strlen(self);
-	char *buf, *self_strptr;
+	data_size_t tlen, len;
+	i32_t i, times;
+	ch3_p buf, self_strptr;
 
 	BIN_CONTENT_CHK(String);
+	len = pr_strlen(self);
 	if (!has_proto(ist, parms[1], OBJ(INT_PROTO))) {
 		raise_exception(ist, OBJ(TYPE_EXC), "multiply times parameter must be an integer");
 		return NULL;
 	}
-	times = (size_t) parms[1]->data.i64;
+	times = int2i32t(ist, parms[1]);
+	if(times < 0) {
+		raise_exception(ist, OBJ(VALUE_EXC), "times parameter must be >= zero");
+		return NULL;
+	}
 	if(times == 0) return NEW_STRING("");
 	if(times == 1) return self;
 	tlen = len*times;
-	buf = pr_malloc(tlen+1);
-	self_strptr = pr2c_strptr(ist, self);
+	buf = pr_malloc(tlen*3);
+	self_strptr = pr_ch3ptr(self);
 	for(i=0; i < times; i++)
-		memcpy(buf+(i*len), self_strptr, len);
-	buf[tlen] = 0;
-	res = NEW_STRINGN(buf, tlen);
+		memcpy(buf+(i*len), self_strptr, len*3);
+	res = NEW_STRING_CH3(buf, tlen);
 	pr_free(buf);
 	return res;
 }
@@ -498,27 +511,21 @@
 }
 
 DEF(String, ord, NULL) {
-	ch3_p ch3p;
 	BIN_CONTENT_CHK(String);
 	if (!pr_strlen(self)) {
 		raise_exception(ist, OBJ(VALUE_EXC), "ord not valid on empty string");
 		return NULL;
 	}
-	if (self->data_type == DATA_TYPE_IMMDATA)
-		ch3p = self->data.str;
-	else
-		ch3p = ((str_p)self->data.ptr)->str;
-	return NEW_INT(ORD(ch3p));
+	return NEW_INT(ORD(pr_ch3ptr(self)));
 }
 
 DEF(String, join, FORM_RPARAM) {
-	char *self_str;
+	obj_p obj, list, str_list;
 	str_p obj_str;
-	obj_p obj, list, str_list;
+	ch3_p self_str, dest_ptr;
 	int i, llen;
 	u32_t j;
 	size_t self_len, tlen;
-	ch3_p dest_ptr;
 
 	BIN_CONTENT_CHK(String);
 	if (!has_proto(ist, parms[1], OBJ(LIST_PROTO))) {
@@ -529,8 +536,8 @@
 	llen = (int) list_len(ist, parms[1]);
 	if (!llen) return NEW_STRING("");
 	str_list = NEW_LIST(llen);
-	self_str = pr2c_strptr(ist, self);
 	self_len = pr_strlen(self);
+	self_str = pr_ch3ptr(self);
 	tlen = 0;
 	for (i=0; i < llen; i++) {
 		obj_p str_obj = call_func0(ist, list_item(ist, list, i), SYM(STR_)); if_exc_return NULL;
@@ -555,18 +562,18 @@
 	for(i=0; i < llen; i++) {
 		obj_p  str_obj = list_item(ist, str_list, i);
 		size_t str_len = pr_strlen(str_obj);
-		char* src_ptr = pr2c_strptr(ist, str_obj);
-		for (j=0; j < str_len; j++, src_ptr++, dest_ptr++) {
-			dest_ptr->b0 = *src_ptr;
-			dest_ptr->b1 = 0;
-			dest_ptr->b2 = 0;
+		ch3_p src_ptr  = pr_ch3ptr(str_obj);
+		for (j=0; j < str_len; j++, dest_ptr++, src_ptr++) {
+			dest_ptr->b0 = src_ptr->b0;
+			dest_ptr->b1 = src_ptr->b1;
+			dest_ptr->b2 = src_ptr->b2;
 		}
 		if (i != llen-1) {
 			src_ptr = self_str;
-			for (j=0; j < self_len; j++, src_ptr++, dest_ptr++) {
-				dest_ptr->b0 = *src_ptr;
-				dest_ptr->b1 = 0;
-				dest_ptr->b2 = 0;
+			for (j=0; j < self_len; j++, dest_ptr++, src_ptr++) {
+				dest_ptr->b0 = src_ptr->b0;
+				dest_ptr->b1 = src_ptr->b1;
+				dest_ptr->b2 = src_ptr->b2;
 			}
 		}
 	}
@@ -579,16 +586,18 @@
 	BIN_CONTENT_CHK(String);
 	if (!has_proto(ist, parms[1], String_OBJ))
 		return call_func1(ist, parms[1], SYM(RIN__QUES), self);
-	if (strstr(pr2c_strptr(ist, parms[1]), pr2c_strptr(ist, self))) return OBJ(PR_TRUE);
-	else						              return OBJ(PR_FALSE);
+	if ( ch3_strstr( pr_ch3ptr(parms[1]), pr_strlen(parms[1]), 
+		             pr_ch3ptr(self),     pr_strlen(self) ) ) return OBJ(PR_TRUE);
+	else						                              return OBJ(PR_FALSE);
 }
 
 DEF(String, notIn__QUES, FORM_RPARAM) {
 	BIN_CONTENT_CHK(String);
 	if (!has_proto(ist, parms[1], String_OBJ))
 		return call_func1(ist, parms[1], SYM(RNOTIN__QUES), self);
-	if (strstr(pr2c_strptr(ist, parms[1]), pr2c_strptr(ist, self))) return OBJ(PR_FALSE);
-	else						              return OBJ(PR_TRUE);
+	if ( ch3_strstr( pr_ch3ptr(parms[1]), pr_strlen(parms[1]), 
+		             pr_ch3ptr(self),     pr_strlen(self) ) ) return OBJ(PR_FALSE);
+	else						                              return OBJ(PR_TRUE);
 }
 
 DEF(String, len, NULL) {
@@ -625,7 +634,7 @@
 DEF(String, find, FPARM2( stringToFind, NULL, indexToStartLooking, NEW_INT(0) )) {
 	size_t str_len;
 	size_t find_len = 0;
-	char *found, *find_ptr = 0, *self_str;
+	ch3_p found, find_ptr = NULL, self_str;
 	size_t start = 0;
 	obj_p result = 0;
 
@@ -642,17 +651,17 @@
 		start = (size_t)int2i32t(ist, parms[3]);
 	}
 
-	find_ptr = pr2c_strptr(ist, parms[1]);
+	find_ptr = pr_ch3ptr(parms[1]);
 	find_len = pr_strlen(parms[1]);
-	if (find_len<1) {
+	if (find_len < 1) {
 		return new_int_obj(ist,0);
 	}
-	self_str = pr2c_strptr(ist, self);
-	found = bin_strstr(self_str+start,str_len,find_ptr,find_len);
+	self_str = pr_ch3ptr(self);
+	found = ch3_strstr(self_str + start, str_len, find_ptr, find_len);
 	if (found) {
-		result = new_int_obj(ist,found-self_str);
+		result = new_int_obj(ist, found - self_str);
 	} else {
-		result = new_int_obj(ist,0);
+		result = new_int_obj(ist, 0);
 	}
 	pr_free(find_ptr);
 	pr_free(self_str);
@@ -664,15 +673,15 @@
 	size_t find_len = 0;
 	size_t repl_len = 0;
 	size_t result_len = str_len;
-	char *buf, *dest_ptr = 0;
+	ch3_p buf, dest_ptr = NULL;
 	obj_p obj=0;
 	str_p obj_str = 0;
-	char* src_ptr = 0;
-	char* find_ptr = 0;
-	char* repl_ptr = 0;
+	ch3_p src_ptr = 0;
+	ch3_p find_ptr = 0;
+	ch3_p repl_ptr = 0;
 	size_t temp_len = 0;
-	char* a_match = 0;
-	char* where_ptr = 0;
+	ch3_p a_match = 0;
+	ch3_p where_ptr = 0;
 
 	BIN_CONTENT_CHK(String);
 
@@ -692,53 +701,52 @@
 		return NULL;
 	}
 	repl_len = pr_strlen(parms[3]);
-	src_ptr  = pr2c_strptr(ist, self);
-	find_ptr = pr2c_strptr(ist, parms[1]);
-	repl_ptr = pr2c_strptr(ist, parms[3]);
+	src_ptr  = pr_ch3ptr(self);
+	find_ptr = pr_ch3ptr(parms[1]);
+	repl_ptr = pr_ch3ptr(parms[3]);
 
 	// This is perhaps not as efficient as it could be.
 
 	// Find the length of the result string.
 	temp_len = str_len;
-	a_match = bin_strstr(src_ptr, temp_len, find_ptr, find_len);
+	a_match = ch3_strstr(src_ptr, temp_len, find_ptr, find_len);
 	while (a_match) {
 		result_len -= find_len;
 		result_len += repl_len;
 		a_match += find_len; // Skip the matching text.
 		temp_len = str_len - (a_match - src_ptr);
-		a_match = bin_strstr(a_match, temp_len, find_ptr, find_len);
+		a_match = ch3_strstr(a_match, temp_len, find_ptr, find_len);
 	}
 
 	// Create the copy.
-	dest_ptr = buf = pr_malloc(sizeof(str_t) + result_len + 1);
-	dest_ptr[result_len] = 0;
+	dest_ptr = buf = pr_malloc(sizeof(str_t) + result_len*3);
 
 	// Fill the replaced copy.
 	temp_len = str_len;
 	where_ptr = src_ptr;
-	a_match = bin_strstr(where_ptr,temp_len,find_ptr,find_len);
+	a_match = ch3_strstr(where_ptr, temp_len, find_ptr, find_len);
 	while (a_match) {
 		// Copy everything from where we were to the beginning of the
 		// match.
 		int frag_len = (int) (a_match - where_ptr);
-		memcpy(dest_ptr,where_ptr,frag_len);
+		memcpy(dest_ptr, where_ptr, frag_len*3);
 		dest_ptr += frag_len;
 
 		// Copy the replacement text.
-		memcpy(dest_ptr,repl_ptr,repl_len);
+		memcpy(dest_ptr, repl_ptr, repl_len*3);
 		dest_ptr += repl_len;
 
 		a_match += find_len; // Skip the matched text.
 		where_ptr = a_match;
 		temp_len = str_len - (a_match - where_ptr);
-		a_match = bin_strstr(a_match,temp_len,find_ptr,find_len);
+		a_match = ch3_strstr(a_match, temp_len, find_ptr, find_len);
 	}
 
 	// Copy any trailing text after the last match.
-	if (where_ptr<src_ptr+str_len) {
-		memcpy(dest_ptr,where_ptr,(src_ptr+str_len)-where_ptr);
+	if (where_ptr < src_ptr + str_len) {
+		memcpy(dest_ptr, where_ptr, ((src_ptr+str_len)-where_ptr)*3);
 	}
-	return NEW_STRINGN(buf, result_len);
+	return NEW_STRING_CH3(buf, result_len);
 }
 
 DEF(String, expandTabs, FPARM1( nSpaces, NEW_INT(8) )) {
@@ -748,9 +756,9 @@
 		obj_p tab = new_string_obj(ist, "\t");
 		obj_p tspace = new_string_obj(ist, " ");
 		obj_p mul_args[]= {NULL, parms[1]};
-		obj_p spcs = Stringmul_(ist,tspace,2,mul_args,0);
+		obj_p spcs = Stringmul_(ist, tspace,2, mul_args, 0);
 		obj_p repl_args[] = {NULL, tab, NULL, spcs};
-		result = Stringreplace(ist,self,4,repl_args,0);
+		result = Stringreplace(ist, self, 4, repl_args, 0);
 		del_unlock(tab);
 		del_unlock(spcs);
 		del_unlock(tspace);
@@ -758,70 +766,48 @@
 	return result;
 }
 
-//===============================
-// ASSUMPTION: if we're using lStrip, rStrip, etc, then
-// we're dealing with null-terminated text strings.
-//===============================
 DEF(String, lStrip, NULL) {
-	char* cstr = pr2c_strptr(ist, self);
-
+	ch3_p ch3p, endp;
+	data_size_t len;
 	BIN_CONTENT_CHK(String);
-
-	while (isspace(*cstr)) {
-		++cstr;
-	}
-	
-	// Create the copy.
-	return new_string_obj(ist, cstr);
+	ch3p = pr_ch3ptr(self);
+	len  = pr_strlen(self);
+	endp = ch3p + len;
+	while (ch3p < endp && IS_SPACE(ch3p)) ch3p++;
+	return new_string_ch3_obj(ist, ch3p, endp-ch3p);
 }
 
 DEF(String, rStrip, NULL) {
-	// Count whitespace at the end.
-	char *self_str, *cstr;
-	size_t result_len = 0;
-
+	ch3_p ch3p, endp;
+	data_size_t len;
 	BIN_CONTENT_CHK(String);
-
-	self_str = pr2c_strptr(ist, self);
-	cstr = self_str + strlen(self_str) - 1;
-	while (cstr >= self_str && isspace(*cstr)) {
-		--cstr;
-	}
-	result_len = cstr - self_str + 1;
-	
-	// Create the copy.
-	return new_string_n_obj(ist, self_str, result_len);
+	ch3p = pr_ch3ptr(self);
+	len  = pr_strlen(self);
+	endp = ch3p + len;
+	while (endp > ch3p && IS_SPACE(endp-1)) endp--;
+	return new_string_ch3_obj(ist, ch3p, endp-ch3p);
 }
 
 DEF(String, strip, NULL) {
-	char *cstr2, *cstr;
-	size_t result_len;
-
+	ch3_p ch3p, endp;
+	data_size_t len;
 	BIN_CONTENT_CHK(String);
-	cstr = pr2c_strptr(ist, self);
-	while (isspace(*cstr)) {
-		++cstr;
-	}
-	// Count whitespace at the end.
-	cstr2 = cstr+strlen(cstr)-1;
-	result_len = 0;
-	while (cstr2 >= cstr && isspace(*cstr2)) {
-		--cstr2;
-	}
-	result_len = cstr2-cstr+1;
-	
-	// Create the copy.
-	return new_string_n_obj(ist,cstr,result_len);
+	ch3p = pr_ch3ptr(self);
+	len  = pr_strlen(self);
+	endp = ch3p + len;
+	while (ch3p < endp && IS_SPACE(ch3p)) ch3p++;
+	while (endp > ch3p && IS_SPACE(endp-1)) endp--;
+	return new_string_ch3_obj(ist, ch3p, endp-ch3p);
 }
 
 DEF(String, split, FORM_RPARAM) {
 	size_t str_len = pr_strlen(self);
 	size_t find_len = 0;
-	char* src_ptr = 0;
-	char* find_ptr = 0;
+	ch3_p src_ptr = 0;
+	ch3_p find_ptr = 0;
 	size_t temp_len = 0;
-	char* a_match = 0;
-	char* where_ptr = 0;
+	ch3_p a_match = 0;
+	ch3_p where_ptr = 0;
 	obj_p next_frag, list_obj = new_list_obj(ist,0);
 
 	BIN_CONTENT_CHK(String);
@@ -831,50 +817,50 @@
 	}
 
 	find_len = pr_strlen(parms[1]);
-	if (find_len<1) {
+	if (find_len < 1) {
 		raise_exception(ist, OBJ(TYPE_EXC), "split: empty separator");
 		return NULL;
 	}
-	src_ptr = pr2c_strptr(ist, self);
+	src_ptr = pr_ch3ptr(self);
 	where_ptr = src_ptr;
-	find_ptr = pr2c_strptr(ist, parms[1]);
+	find_ptr = pr_ch3ptr(parms[1]);
 
 	temp_len = str_len;
-	a_match = bin_strstr(src_ptr,temp_len,find_ptr,find_len);
+	a_match = ch3_strstr(src_ptr, temp_len, find_ptr, find_len);
 	while (a_match) {
 		// Make new string from where_ptr to a_match.
-		obj_p next_frag = new_string_n_obj(ist,where_ptr,a_match-where_ptr);
-		list_append(ist,list_obj,next_frag);
+		obj_p next_frag = new_string_ch3_obj(ist, where_ptr, a_match-where_ptr);
+		list_append(ist, list_obj, next_frag);
 
 		a_match += find_len; // Skip the matching text.
 		where_ptr = a_match;
  		temp_len = str_len - (a_match - src_ptr);
-		a_match = bin_strstr(a_match,temp_len,find_ptr,find_len);
+		a_match = ch3_strstr(a_match, temp_len, find_ptr, find_len);
 	}
 
 	// Copy any trailing text after the last match.
-	next_frag = new_string_n_obj(ist,where_ptr,str_len-(where_ptr-src_ptr));
-	list_append(ist,list_obj,next_frag);
+	next_frag = new_string_ch3_obj(ist, where_ptr, str_len-(where_ptr-src_ptr));
+	list_append(ist, list_obj, next_frag);
 	
 	return list_obj;
 }
 
-DEF(String, iter_, NULL) {
-	obj_p gen_obj;
-	BIN_CONTENT_CHK(String);
-	gen_obj = NEW_OBJ(StringGen_OBJ);
-	SET_TYPE_IF_EXC(StringGen_OBJ, gen_obj, DATA_TYPE_DATAPTR) return NULL;
-	gen_obj->data.ptr = pr2c_strptr(ist, self);
-	set_attr(ist, gen_obj, sym(ist, "savedString"), self);
-	return gen_obj;
-}
-
 DEF(String, objList_, FORM_RPARAM) {
 	return parms[1];
 }
 
 //********************************* STRINGGEN MODULE **************************
 
+typedef struct {
+	data_size_t size;
+	ch3_p		ptr;
+	ch3_t		str[];
+} str_gen_t;
+
+typedef str_gen_t* str_gen_p;
+
+#define str_gen_len(strgenp) (((strgenp->size)-sizeof(str_gen_t))/sizeof(ch3_t))
+
 MODULE_START(StringGen)
 {
 	StringGen_OBJ = NEW_OBJ(NULL);
@@ -882,20 +868,38 @@
 	set_obj_id(StringGen_OBJ, *, StringGen);
 }
 
+DEF(String, iter_, NULL) {
+	obj_p gen_obj;
+	data_size_t i, len;
+	str_gen_p strgenp;
+	ch3_p srcp, dstp;
+	BIN_CONTENT_CHK(String);
+	gen_obj = NEW_OBJ(StringGen_OBJ);
+	SET_TYPE_IF_EXC(StringGen_OBJ, gen_obj, DATA_TYPE_DATAPTR) return NULL;
+	len  = pr_strlen(self);
+	srcp = pr_ch3ptr(self);
+	gen_obj->data.ptr = strgenp = pr_malloc(sizeof(str_gen_t) + len*sizeof(ch3_t));
+	strgenp->size = sizeof(str_gen_t) + len*sizeof(ch3_t);
+	strgenp->ptr  = dstp = strgenp->str;
+	for(i=0; i < len; i++, dstp++, srcp++) {
+		dstp->b0 = srcp->b0;
+		dstp->b1 = srcp->b1;
+		dstp->b2 = srcp->b2;
+	}
+	return gen_obj;
+}
+
 DEF(StringGen, next, NULL) {
-        int ch;
         obj_p res = NULL;
-        char* res_str;
+        str_gen_p strgenp;
 		BIN_CONTENT_CHK(StringGen);
         def_write_lock(self);
-        if ((ch = *((char*)self->data.ptr))) {
-				self->data.ptr = (i64_t *)(((char*)self->data.ptr) + 1);
-                res = NEW_OBJ(String_OBJ);
-                res_str = (char*)obj_malloc(ist, OBJ(STRING_PROTO), res, 2);
-                res_str[0] = ch;
-                res_str[1] = 0;
-        } else
+		strgenp = self->data.ptr;
+		if (strgenp->ptr == (strgenp->str)+str_gen_len(strgenp)) {
                 raise_exception(ist, OBJ(STOP_ITERATION_EXC), NULL);
+				return NULL;
+		}
+		res = new_string_ch3_obj(ist, strgenp->ptr++, 1);
         def_write_unlock(self);
         return res;
 }