rev 448 - trunk/src
SVN User <[email protected]> Mon, 03 May 2004 11:04:29 -0400
| Newsgroups | gmane.comp.lang.prothon.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: jknapka
Date: 2004-05-03 11:04:26 -0400 (Mon, 03 May 2004)
New Revision: 448
Modified:
trunk/src/builtins-string.c
Log:
Implemented a number of Python's string methods.
Modified: trunk/src/builtins-string.c
===================================================================
--- trunk/src/builtins-string.c 2004-05-03 03:25:30 UTC (rev 447)
+++ trunk/src/builtins-string.c 2004-05-03 15:04:26 UTC (rev 448)
@@ -53,6 +53,7 @@
// builtins.c
+#include <ctype.h>
#include <stdio.h>
#include <string.h>
@@ -353,7 +354,7 @@
} else {
obj_str = obj_malloc(ist, OBJ(STRING_PROTO), obj, sizeof(pr_str_t)+tlen+1);
if(!obj_str) {
- raise_exception(ist, OBJ(OUTOFMEMORY_EXC), "memory allocation failed for string multiplication");
+ raise_exception(ist, OBJ(OUTOFMEMORY_EXC), "memory allocation failed for string join");
return NULL;
}
obj_str->len = tlen;
@@ -407,7 +408,312 @@
return NEW_INT(sizeof(pr_str_t) + pr_strlen(self) + 1);
}
+// Generic case-changer function.
+static obj_p changeCase(isp ist,obj_p self,int (*changer)(int), size_t howMany) {
+ size_t str_len = pr_strlen(self), ii = 0;
+ char* dest_ptr = 0;
+ obj_p obj=0;
+ pr_str_p obj_str=0;
+ obj = NEW_OBJ(String_OBJ);
+ obj_str = obj_malloc(ist, OBJ(STRING_PROTO), obj, sizeof(pr_str_t)+str_len+1);
+ if(!obj_str) {
+ raise_exception(ist, OBJ(OUTOFMEMORY_EXC),
+ "memory allocation failed for string.changeCase (used by lower(), upper(), etc.)");
+ return NULL;
+ }
+ obj_str->len = str_len;
+ dest_ptr = obj_str->str;
+
+ // Fill the copy.
+ char* src_ptr = pr_strptr(self);
+ for (ii=0; ii<str_len; ++ii) {
+ if (ii<howMany) {
+ dest_ptr[ii] = (char)(*changer)(src_ptr[ii]);
+ } else {
+ dest_ptr[ii] = src_ptr[ii];
+ }
+ }
+ dest_ptr[str_len] = 0;
+
+ return obj;
+}
+
+DEF(String, lower, NULL) {
+ return changeCase(ist,self,&tolower,pr_strlen(self));
+}
+
+DEF(String, upper, NULL) {
+ return changeCase(ist,self,&toupper,pr_strlen(self));
+}
+
+DEF(String, capitalize, NULL) {
+ return changeCase(ist,self,&toupper,1);
+}
+
+// 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;
+ while (looking_at < hs_end) {
+ if (*lookfor == *looking_at) {
+ // Matched a character.
+ ++lookfor;
+ if (lookfor == ndl_end) {
+ // Matched the whole string. It started lneedle-1
+ // characters before the character we're looking at
+ // now.
+ return looking_at + 1 - lneedle;
+ }
+ } else {
+ // No match.
+ if (lookfor > needle) {
+ // We had recognized the beginning of a match. We must
+ // return to the character after the location at which
+ // the non-match began.
+ looking_at -= lookfor-needle;
+ lookfor = needle;
+ }
+ }
+ ++looking_at;
+ }
+ return 0;
+}
+
+#define Int_value(objid) (objid->data.i64)
+DEF(String, find, FORM_PARAM2) {
+ size_t str_len = pr_strlen(self);
+ size_t find_len = 0;
+ char* find_ptr = 0;
+ size_t start = 0;
+ obj_p result = 0;
+
+ if (!has_proto_QUES(ist, parms[1], String_OBJ)) {
+ raise_exception(ist, OBJ(TYPE_EXC), "find function parameter 1 must be a string");
+ return NULL;
+ }
+ if (parms[3]) {
+ if (!has_proto_QUES(ist, parms[3], OBJ(INT_PROTO))) {
+ raise_exception(ist, OBJ(TYPE_EXC), "find function parameter 2 must be an integer");
+ return NULL;
+ } else {
+ start = (size_t)Int_value(parms[3]);
+ }
+ }
+
+ find_ptr = pr_strptr(parms[1]);
+ find_len = pr_strlen(parms[1]);
+ if (find_len<1) {
+ return new_int_obj(ist,0);
+ }
+ char* found = bin_strstr(pr_strptr(self)+Int_value(parms[3]),str_len,find_ptr,find_len);
+ if (found) {
+ result = new_int_obj(ist,found-pr_strptr(self));
+ } else {
+ result = new_int_obj(ist,0);
+ }
+
+ return result;
+}
+
+DEF(String, replace, FORM_PARAM2) {
+ size_t str_len = pr_strlen(self);
+ size_t find_len = 0;
+ size_t repl_len = 0;
+ size_t result_len = str_len;
+ char* dest_ptr = 0;
+ obj_p obj=0;
+ pr_str_p obj_str = 0;
+ char* src_ptr = 0;
+ char* find_ptr = 0;
+ char* repl_ptr = 0;
+ size_t temp_len = 0;
+ char* a_match = 0;
+ char* where_ptr = 0;
+
+ if (!has_proto_QUES(ist, parms[1], String_OBJ)) {
+ raise_exception(ist, OBJ(TYPE_EXC), "replace function parameter 1 must be a string");
+ return NULL;
+ }
+ if (!has_proto_QUES(ist, parms[3], String_OBJ)) {
+ raise_exception(ist, OBJ(TYPE_EXC), "replace function parameter 2 must be a string");
+ return NULL;
+ }
+
+ find_len = pr_strlen(parms[1]);
+ if (find_len>str_len) return self;
+ if (find_len<1) {
+ raise_exception(ist, OBJ(TYPE_EXC), "replace: empty search string");
+ return NULL;
+ }
+ repl_len = pr_strlen(parms[3]);
+ src_ptr = pr_strptr(self);
+ find_ptr = pr_strptr(parms[1]);
+ repl_ptr = pr_strptr(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);
+ 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);
+ }
+
+ // Create the copy.
+ // Create the copy.
+ obj = NEW_OBJ(String_OBJ);
+ if (result_len < IMMEDIATE_DATA_LEN) {
+ obj->data_type = DATA_TYPE_IMMDATA;
+ obj->imm_data_len = (int) result_len;
+ dest_ptr = obj->data.str;
+ } else {
+ obj_str = obj_malloc(ist, OBJ(STRING_PROTO), obj, sizeof(pr_str_t)+result_len+1);
+ if(!obj_str) {
+ raise_exception(ist, OBJ(OUTOFMEMORY_EXC), "memory allocation failed for string.replace");
+ return NULL;
+ }
+ obj_str->len = result_len;
+ dest_ptr = obj_str->str;
+ }
+
+ // Fill the replaced copy.
+ temp_len = str_len;
+ where_ptr = src_ptr;
+ a_match = bin_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 = a_match-where_ptr;
+ memcpy(dest_ptr,where_ptr,frag_len);
+ dest_ptr += frag_len;
+
+ // Copy the replacement text.
+ memcpy(dest_ptr,repl_ptr,repl_len);
+ 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);
+ }
+
+ // 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);
+ }
+
+ return obj;
+}
+
+DEF(String, expandtabs, NULL) {
+ // FIX ME: should accept an int arg (default 8) telling how many
+ // spaces per tab.
+ obj_p tab = new_string_obj(ist,"\t");
+ obj_p spcs = new_string_obj(ist," ");
+ obj_p args[] = {NULL,tab,NULL,spcs};
+ obj_p result = Stringreplace( ist, self, 2, args, 0 );
+ del_unlock(tab);
+ del_unlock(spcs);
+ 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 = pr_strptr(self);
+ while (isspace(*cstr)) {
+ ++cstr;
+ }
+
+ // Create the copy.
+ return new_string_obj(ist,cstr);
+}
+
+DEF(String, rstrip, NULL) {
+ // Count whitespace at the end.
+ char* cstr = pr_strptr(self)+pr_strlen(self)-1;
+ size_t result_len = 0;
+ while (isspace(*cstr)) {
+ --cstr;
+ }
+ result_len = cstr-pr_strptr(self)+1;
+
+ // Create the copy.
+ return new_string_n_obj(ist,pr_strptr(self),result_len);
+}
+
+DEF(String, strip, NULL) {
+ char* cstr = pr_strptr(self);
+ while (isspace(*cstr)) {
+ ++cstr;
+ }
+
+ // Count whitespace at the end.
+ char* cstr2 = pr_strptr(self)+pr_strlen(self)-1;
+ size_t result_len = 0;
+ while (isspace(*cstr2)) {
+ --cstr2;
+ }
+ result_len = cstr2-cstr+1;
+
+ // Create the copy.
+ return new_string_n_obj(ist,cstr,result_len);
+}
+
+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;
+ size_t temp_len = 0;
+ char* a_match = 0;
+ char* where_ptr = 0;
+ obj_p list_obj = new_list_obj(ist,0);
+
+ if (!has_proto_QUES(ist, parms[1], String_OBJ)) {
+ raise_exception(ist, OBJ(TYPE_EXC), "split function parameter 1 must be a string");
+ return NULL;
+ }
+
+ find_len = pr_strlen(parms[1]);
+ if (find_len<1) {
+ raise_exception(ist, OBJ(TYPE_EXC), "split: empty separator");
+ return NULL;
+ }
+ src_ptr = pr_strptr(self);
+ where_ptr = src_ptr;
+ find_ptr = pr_strptr(parms[1]);
+
+ temp_len = str_len;
+ a_match = bin_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);
+
+ 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);
+ }
+
+ // Copy any trailing text after the last match.
+ obj_p next_frag = new_string_n_obj(ist,where_ptr,str_len-(where_ptr-src_ptr));
+ list_append(ist,list_obj,next_frag);
+
+ return list_obj;
+}
+
//********************************* STRINGGEN MODULE **************************
MODULE_START(StringGen)
@@ -435,8 +741,6 @@
return res;
}
-
-
//********************************* MODULES INIT ******************************
MAIN_MODULE_INIT(String)
@@ -461,6 +765,16 @@
MODULE_ADD_SYM(String, __delItem__);
MODULE_ADD_SYM(String, __objList__);
MODULE_ADD_SYM(String, __cDataLen__);
+ MODULE_ADD_SYM(String, lower);
+ MODULE_ADD_SYM(String, upper);
+ MODULE_ADD_SYM(String, replace);
+ MODULE_ADD_SYM(String, capitalize);
+ MODULE_ADD_SYM(String, expandtabs);
+ MODULE_ADD_SYM(String, lstrip);
+ MODULE_ADD_SYM(String, rstrip);
+ MODULE_ADD_SYM(String, strip);
+ MODULE_ADD_SYM(String, split);
+ MODULE_ADD_SYM(String, find);
MODULE_SUB_INIT(StringGen);
MODULE_ADD_SYM(StringGen, next);