I thought I would mention that the string library Charles wrote is in the abrivated version of C BASIC. Lovin It!
Basic.c
#include <stdlib.h>
#include <stdio.h>
#define function
#define method
#define gosub
#define dim
#define as
#define to
#define limit
#define step
#define then
#define procedure void
#define sub void
#define begin {
#define end }
#define and &&
#define or ||
#define class typedef struct
#define types typedef struct
#define member ->
#define addressof &
#define has =
#define incr ++
#define decr --
#define next ++
#define prior --
#define byref *
#define ref void*
#define references = &
#define FreeSpace free
#define FUNCTION
#define BEGIN_FUNCTION {
#define END_FUNCTION }
#define SUB void
#define BEGIN_SUB {
#define END_SUB }
#define RETURN return
#define CALL
#define AND &&
#define OR ||
#define MOD %
#define DIM
#define AS
#define LET
#define INCR ++
#define DECR --
#define IF if
#define BEGIN_IF {
#define THEN {
#define THEN_DO
#define ELSE } else {
#define END_IF }
#define FOR for
#define TO ;
#define STEP ;
#define BEGIN_FOR {
#define NEXT }
#define SELECT_CASE switch
#define BEGIN_SELECT {
#define CASE case
#define _TO_ ...
#define END_CASE break;
#define CASE_ELSE default:
#define END_SELECT }
#define DO do {
#define WHILE } while
#define create(A,B,C) A B=NewSpace((C)*sizeof(*B))
#define copy(A,B,C) CopyBytes((char*)A,(char*)B,C)
#define HiWord(n) ((n>>16)and 0xffff)
#define LoWord(n) (n and 0xffff)
//indexbase 1
function void* NewSpace(int count)
begin
char *v = malloc(count);
int i;
for (i=0; limit i<count; step incr i) v[i]=0; // set chars to null
return v;
end
sub CopyBytes(void*dv,void*sv,int count)
begin
char*s=sv;
char*d=dv;
int i;
for (i=0; limit i<count; step incr i)
begin
*d=*s;
next d;
next s;
end
end
Output
jrs@laptop:~/C_BASIC/cbstrlib$ ./cbstrtest
LO
HELLO
HELLOHELLOHELLO
9
helloLOhellohello
hellohellohello
42.000000
42.000000
AbcAbcAbcAbcAbcAbcAbc
LOLOLOLOLOLOLO
AbcAbcAbcAbcAbcAbcAbc
<
>
Hello World!
<HELLO WORLD!>
<<HELLO WORLD!>>
HELLO
HELLOH
jrs@laptop:~/C_BASIC/cbstrlib$
ClassString.c
#include "Basic.c"
/*
ENTITIES:
=========
StringType
CharArray
StringClass
StringClassTable
StringMethods
StringObject
StringParameters
PROCEDURES
==========
New
Free
METHODS:
========
Get
Set
Move
Action
Show
(other Operations...)
Translate
Rotate
*/
typedef char StringType,*CharArray;
class StringClassStruct
begin
ref StringMethods;
int count;
int width;
int nbytes;
end
StringClass,*StringObject;
types StringClassTableStruct
begin
method StringObject (byref Redim) (StringObject*pthis, int n, int wi, int cnt);
method StringObject (byref Set) (StringObject*pthis, StringObject s);
method char* (byref GetChars)(char**r, StringObject this, int wi);
method StringObject (byref SetChars)(StringObject*pthis, char*c, int le, int wi);
method StringObject (byref GetMid) (StringObject*r, StringObject this, int s, int le, int wi);
method StringObject (byref SetMid) (StringObject*pthis, int i, StringObject s);
method StringObject (byref Join) (StringObject*pthis, int n,...);
method StringObject (byref Repeat) (StringObject*pthis, StringObject s ,int n);
method StringObject (byref Replace) (StringObject*pthis, StringObject f , StringObject r);
method StringObject (byref Ucase) (StringObject*r, StringObject this);
method StringObject (byref Lcase) (StringObject*r, StringObject this);
method StringObject (byref Ltrim) (StringObject*r, StringObject this);
method StringObject (byref Rtrim) (StringObject*r, StringObject this);
method StringObject (byref Insert) (StringObject*pthis, StringObject s, int i);
method StringObject (byref Delete) (StringObject*pthis, int i, int le);
method StringObject (byref Chr) (StringObject*r, int a, int wi);
method StringObject (byref Str) (StringObject*r, double d);
method int (byref Show) (StringObject this);
method int (byref Asc) (StringObject this, int i); // also supports wide chars
method int (byref Instr) (int i, StringObject this, StringObject k);
method double (byref Val) (StringObject this);
end
StringClassTable,*StringMethods;
#define Left(S,I) GetMid(S,1,(I),-1)
#define Right(S,I) GetMid(S,-(I),-1,-1)
#define aChr(R,N) Chr(R,N,1)
#define wChr(R,N) Chr(R,N,2)
sub CopyWidth(char*t, int tw, char*s, int sw,int count)
begin
int i;
if(tw==2)
begin
if (sw==2)
begin
short*ss=(short*) s;
short*ts=(short*) t;
for (i=0; limit i<count; step incr i)
begin
*ts=*ss;
incr ts;
incr ss;
end
return;
end
if (sw==1)
begin
short*ts=(short*) t;
for (i=0; limit i<count; step incr i)
begin
*ts=*s;
incr ts;
incr s;
end
return;
end
end
// otherwise copy lower bytes only
for (i=0; limit i<count; step incr i)
begin
*t=*s;
t+=tw;
s+=sw;
end
end
function int ByteLen(char*s)
begin
int i=0;
while (s[i] !=0 ) i++;
return i;
end
function int WordLen(char*s)
begin
short*w=(short*) s;
int i=0;
while (w[i] !=0 ) i++;
return i;
end
function int WordFill(char*s, int le, short c)
begin
short*w=(short*) s;
int i=0;
while (le--) w[i++]=c;
end
function CharArray strptr(StringObject s)
begin
return (void*) s + sizeof(StringClass);
end
function StringObject StringTransfer(StringObject*r,StringObject s)
begin
if (*r==s) return s; // no transfer
if (*r != 0 ) then free(*r); // free old string
*r=s; // ref new string
return s; // return new string
end
function char* CharTransfer(char**r, char*s)
begin
if (*r==s) return s; // no transfer
if (*r != 0 ) then free(*r); // free old string
*r=s; // ref new string
return s; // return new string
end
function StringMethods StringClassTableBuild();
function StringObject NewString(int nc, int wi)
begin
static StringMethods vm;
if (vm==0) then vm = StringClassTableBuild();
StringObject this has NewSpace(sizeof(StringClass)+2+nc*wi);
this->StringMethods = vm;
this->count = nc;
this->width = wi;
this->nbytes=nc*wi;
return this;
end
sub StringFree(StringObject*pthis)
begin
StringObject this=*pthis;
if (this==0) FreeSpace(this);
*pthis=0;
end
//methods
method StringObject StringRedim(StringObject*pthis, int nc,int wi,int cnt)
begin
StringObject this=*pthis;
int tc=0;
int tw=1;
int nb=0;
if (this)
begin
tc=this->count;
tw=this->width;
nb=this->nbytes;
end
if (wi<0) then wi=tw; //default width
if ((nb<nc*wi)or(wi != tw)or(nb==0))
begin
StringObject v=NewString(nc,wi);
int n=nc;
if (n>tc) n=tc;
if ((this)and(cnt)) then CopyWidth(to strptr(v), wi, strptr(this), tw, n+1);
return StringTransfer(pthis,v);
end
else
begin
this member count = nc;
return this;
end
end
method StringObject StringSet(StringObject*pthis, StringObject s)
begin
StringObject this=*pthis;
if (this->count < s->count) then this = NewString(s->count,this->width);
CopyWidth(strptr(this),this->width,strptr(s),s->width,s->count);
return StringTransfer(pthis,this);
end
method char* StringGetChars(char**r, StringObject this, int wi)
begin
char*s = NewSpace(wi * this->count +2);
CopyWidth(s, wi, strptr(this), this->width, this->count+1);
return CharTransfer(r,s);
end
method StringObject StringSetChars(StringObject*pthis, char*s, int le, int wi)
begin
StringObject this=*pthis;
if (le<0) then
begin
if (wi==2)
begin
le=WordLen(s);
end
else
begin
le=ByteLen(s);
end
end
StringObject t=this;
if (this->nbytes < le*wi) then t = NewString(le,this->width);
char*k=strptr(t);
int tw = t->width;
CopyWidth(k, tw, s, wi, le); // autoconvert
t->count=le;
k+=le*tw;
k[0]=0; // null terminators
k[1]=0;
return StringTransfer(pthis,t);
end
method StringObject StringGetMid(StringObject*r, StringObject this, int i, int le, int wi)
begin
int lt=this member count;
if (wi<0) then wi=this->width; // default to this width
if (le<0) then le=lt; // default max
if (i<0) then i+=lt+1; // offset from right
decr i; // indexbase 0
if (le+i>lt) then le=lt-i; // clip length
if (i<0) then i=0; //clamp lower offset
StringObject s=*r;
if ((s==0)or(s->nbytes < le*wi)) then s = NewString(le,wi);
char*k=strptr(s);
CopyWidth(k, wi, strptr(this)+i*this->width, this->width, le);
k+=le*wi;
k[0]=0;
k[1]=0;
s->count=le;
s->width=wi;
return StringTransfer(r,s);
end
method StringObject StringSetMid(StringObject*pthis, int i, StringObject s)
begin
StringObject this=*pthis;
int lt=this member count;
int le=s member count;
if (i<0) then i+=1+lt;
decr i;
char*k = strptr(this)+ i * this->width;
if (le+i>=lt) then le = lt-i;
CopyWidth(k, this->width, strptr(s), s->width, le);
return this;
end
method StringObject StringJoin(StringObject*pthis,int n,...)
begin
StringObject c = *pthis;
int ne=0;
int i;
char* k;
int wid=1;
StringObject *p=(StringObject*) addressof n;
StringObject s;
int tot=0;
for (i=1; to i<=n; step incr i)
begin
s=p[i];
tot+=s->count;
if (s->width == 2) then wid=2;
if(s==c) then ne=1; // force new join-buffer
end
if ((ne==1)or(c==0)or( c->nbytes < tot*wid)) then c=NewString(tot,wid);
char* m = strptr(c);
for (i=1; to i<=n; step incr i)
begin
s=p[i];
k=strptr(s);
CopyWidth(m, wid, k, s->width, s->count);
m+=(s->count * wid);
end
m[0]=0; // terminating null byte
m[1]=0; // terminating null byte (extra for wide strings)
c->count = tot;
c->width = wid;
return StringTransfer(pthis,c);
end
method StringObject StringRepeat(StringObject*pthis, StringObject s ,int n)
begin
int i;
char* k=strptr(s);
int tot=s->count*n;
int wid=s->width;
StringObject c = *pthis;
if ((c==0)or( c->nbytes < tot*wid)) then c=NewString(tot,wid);
char* m=strptr(c);
for (i=1; to i<=n; step incr i)
begin
CopyWidth(m, wid, k, s->width, s->count);
m+=(s->count * wid);
end
m[0]=0; // terminating null byte
m[1]=0; // terminating null byte (extra for wide strings)
c->count = tot;
c->width = wid;
return StringTransfer(pthis,c);
end
method StringObject StringLcase(StringObject*r, StringObject this)
begin
int i;
int w=this->width;
int n=this->count;
StringObject s=*r;
if ((s==0)or(s != this)) then s = StringSet(&s,this);
char*c = strptr(s);
char a;
for (i=0; to limit i<n; incr i)
begin
a=*c;
if ((a>65)and(a<91)) then *c=a+32;
c+=w;
end
return StringTransfer(r,s);
end
method StringObject StringUcase(StringObject*r, StringObject this)
begin
int i;
int w=this->width;
int n=this->count;
StringObject s=*r;
if ((s==0)or(s != this)) then s = StringSet(&s,this);
char*c = strptr(s);
char a;
for (i=0; to limit i<n; incr i)
begin
a=*c;
if ((a>96)and(a<123)) then *c=a-32;
c+=w;
end
if (*r != this) then return StringTransfer(r,s);
return this;
end
method StringObject StringLtrim(StringObject*r, StringObject this)
begin
int i;
StringObject u=*r;
int w=this->width;
int n=this->count;
char*c = strptr(this);
if (w<2)
begin
i=0;
while (i++ < n)
begin
if (*c>32) then break;
c+=w;
end
return StringTransfer(r,StringGetMid(&u,this,i,-1,w));
end
else
begin
i=0;
while (i++ <n)
begin
if ((c[0]>32)or(c[1] != 0)) then break;
c+=w;
end
return StringTransfer(r,StringGetMid(&u,this,(i>>1)+1,-1, w));
end
end
method StringObject StringRtrim(StringObject*r, StringObject this)
begin
int i;
StringObject u=*r;
int w=this->width;
int n=this->count;
char*c = w * n - w + strptr(this);
if (w<2)
begin
i=n;
while(i-- >0)
begin
if (*c>32) then break;
decr c;
end
return StringTransfer(r,StringGetMid(&u,this, 1, i+1, -1));
end
else
begin
i=n;
while (i-- >0)
begin
if ((c[0]>32)or(c[1] != 0)) then break;
c+=w;
end
return StringTransfer(r,StringGetMid(&u,this, 1, (i>>1)+1, -1));
end
end
method StringObject StringInsert(StringObject*pthis, StringObject s, int i)
begin
StringObject this=*pthis;
int c=this->count;
int w=this->width;
StringObject tl=NewString(c,w);
StringObject tr=NewString(c,w);
StringJoin(pthis,3,StringGetMid(&tl,this,1,i-1,w), s, StringGetMid(&tr,this,i,-1,w));
StringFree(&tl);
StringFree(&tr);
return *pthis;
end
method StringObject StringDelete(StringObject*pthis, int i, int le)
begin
StringObject this=*pthis;
int c=this->count;
int w=this->width;
StringObject tl=NewString(c,w);
StringObject tr=NewString(c,w);
StringJoin(pthis,2,StringGetMid(&tl,this,1,i-1,w), StringGetMid(&tr,this,i+le,-1,w));
StringFree(&tl);
StringFree(&tr);
return *pthis;
end
method StringObject StringChr(StringObject*r, int a, int wi)
begin
int le=wi;
StringObject s=*r;
if ((s==0)or(s->nbytes < le*wi)) then s = NewString(le,wi);
s->count=le;
s->width=wi;
short*k=(short*) strptr(s);
*k=a;
return StringTransfer(r,s);
end
method StringObject StringStr(StringObject*r, double d)
begin
int wi=1;
int le=32;
StringObject s=*r;
if ((s==0)or(s->nbytes < le*wi)) then s = NewString(le,wi);
char*k=strptr(s);
sprintf(k,"%f",d);
s->count=ByteLen(k);
s->width=wi;
return StringTransfer(r,s);
end
method int StringShow(StringObject this)
begin
CharArray w=strptr(this);
printf("%s\n", w); // itr wide chars
end
method int StringAsc(StringObject this, int i) // also supports wide chars
begin
if (i<0) then i+=this->count+1; // offset from right
if ((i>this->count)or(i<1)) then return 0; // out of range
decr i; // indexbase 0
int wi=this->width;
if (wi==1) then return *(strptr(this)+i);
if (wi==2)
begin
short *a = (short*) strptr(this)+i*2;
return *a;
end
end
method int StringInstr(int i, StringObject this, StringObject k)
//MATCHING MIXED WIDTHS BUT ONLY ON THE LOWER BYTE
begin
char*tb = strptr(this);
char*tc=tb;
char*kc=strptr(k);
char*te=tc+this->count*this->width;
char*ke=kc+k->count*k->width;
if (i > this->count) then return 0; // offset past end
if (this->count==0) then return 0; // null search string
if (k->count==0) then return i; // null keyword
if (i<0) then i+=this->count+1; // offset from right
decr i; //indexbase 0
tc+=i*this->width; // offset
char*td;
char*kd;
int tw=this->width;
int kw=k->width;
while (tc<te)
begin
if (*tc==*kc)
begin
td=tc;
kd=kc;
while (*td==*kd)
begin
td+=tw;
kd+=kw;
if (kd==ke) then return ((tc-tb)>>(tw-1))+1; // match complete
if (td==te) then return 0; // end of main string
if (*td==*tc) then tc=td-tw; // possible next match
end
end
tc+=tw;
end
end
method double StringVal(StringObject this)
begin
double d;
sscanf(strptr(this),"%lf ",&d);
return d;
end
method StringObject StringReplace(StringObject*pthis, StringObject f , StringObject r)
begin
StringObject this=*pthis;
if ((this==0)or(f==0)or(r==0)) then return this;
if ((this->count==0)or(f->count==0)) then return this;
int n=0;
int i=1;
while (i)
begin
i=StringInstr(i,this,f);
if (i)
begin
n++;
i+=f->count;
end
end
n *= (r->count - f->count);
int tot = n + this->count;
StringObject c = NewString(tot, this->width);
char* m = strptr(c);
int b=1,j=1;
while (j)
begin
j=StringInstr(b,this,f);
if (j)
begin
if (j>b) then CopyWidth(m, c->width,strptr(this)+b-1,this->width,j-b);
m += c->width * (j-b);
CopyWidth(m,c->width,strptr(r),r->width,r->count);
m += c->width * r->count;
b=j + f->count; // skip by keyword length
end
end
// remainder
j = this->count + 1;
if (j>b)
begin
CopyWidth(m,c->width,strptr(this)+b-1,this->width,j-b);
m += c->width * (j-b);
end
m[0]=0; // terminating null byte
m[1]=0; // terminating null byte (extra for wide strings)
return StringTransfer(pthis,c);
end
function StringMethods StringClassTableBuild()
begin
static StringClassTable t;
StringMethods vm references t;
vm->Redim references method StringRedim;
vm->Set references method StringSet;
vm->GetChars references method StringGetChars;
vm->SetChars references method StringSetChars;
vm->GetMid references method StringGetMid;
vm->SetMid references method StringSetMid;
vm->Join references method StringJoin;
vm->Repeat references method StringRepeat;
vm->Replace references method StringReplace;
vm->Ucase references method StringUcase;
vm->Lcase references method StringLcase;
vm->Ltrim references method StringLtrim;
vm->Rtrim references method StringRtrim;
vm->Insert references method StringInsert;
vm->Delete references method StringDelete;
vm->Chr references method StringChr;
vm->Str references method StringStr;
vm->Show references method StringShow;
vm->Asc references method StringAsc;
vm->Instr references method StringInstr;
vm->Val references method StringVal;
return vm;
end
function TestStrings()
begin
dim as int char8=1, char16=2, all=-1;
dim as StringObject uo=NewString(0,char8);
dim as StringObject vo=NewString(0,char8);
dim as StringObject wo=NewString(100,char8);
dim as StringMethods sm=vo->StringMethods;
sm->Show(vo);
sm->SetChars(&uo,"LO",all,char8);
sm->SetChars(&vo," HellO ",all,char8);
sm->Ltrim(&vo,vo);
sm->Rtrim(&vo,vo);
sm->Ucase(&vo,vo);
sm->Join(&wo,3,vo,vo,vo);
sm->Show(uo);
sm->Show(vo);
sm->Show(wo);
printf("%i\n",sm->Instr(6,wo,uo));
sm->Lcase(&wo,wo);
sm->Insert(&wo,uo,6);
sm->Show(wo);
sm->Delete(&wo,6,2);
sm->Show(wo);
sm->Str(&vo,42.0);
sm->Show(vo);
double v=sm->Val(vo);
printf("%f\n",v);
sm->SetChars(&vo,"Abc",all,char8);
sm->Repeat(&wo,vo,7);
sm->Show(wo);
sm->Replace(&wo,vo,uo);
sm->Show(wo);
sm->Replace(&wo,uo,vo);
sm->Show(wo);
sm->SetChars(&uo,"<",all,char8);
sm->SetChars(&vo,">",all,char8);
sm->SetChars(&wo," Hello World! ",all,char8);
sm->Show(uo);
sm->Show(vo);
sm->Show(wo);
sm->Join(&wo,3,uo,sm->Ltrim(&wo,sm->Rtrim(&wo,sm->Ucase(&wo,wo))),vo);
sm->Show(wo);
sm->Join(&wo,3,uo,wo,vo);
sm->Set(&vo,wo);
sm->Show(vo);
sm->GetMid(&vo,wo,3,6,1);
sm->Show(vo);
sm->SetMid(&vo,6,vo);
sm->Show(vo);
StringFree(&uo);
StringFree(&vo);
StringFree(&wo);
end
function int main()
begin
TestStrings();
end