static const char COPYRIGHT[] = "wyrm-bytes - Copyright (C) 2002 SM Ryan. All rights reserved.";
#include "wyrm-bytes.h"
#include "wyrm-io.h"
static int bytesCommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]);
int wyrm_bytesCommandInit(Intr intr) {
char package[] =
"namespace eval ::wyrm {\n"
" namespace export bytes\n"
"}\n";
Tcl_CreateObjCommand(intr,"::wyrm::bytes",bytesCommand,0,0);
return Tcl_Eval(intr,package);
}
static int position(Intr intr,Obj P,int m,int *offset) {
chars OFFSET = Tcl_GetStringFromObj(P,0); int bias;
if (strbegins("end",OFFSET)) {
bias = m-1; OFFSET += 3;
}else
bias = 0;
if (!*OFFSET)
*offset = 0;
else if (Tcl_GetInt(intr,OFFSET,offset)!=TCL_OK)
return TCL_ERROR;
*offset += bias;
return TCL_OK;
}
static int range(Intr intr,int N,Tcl_Obj *const P[],int m,int *from,int *len) {
if (position(intr,P[0],m,from)!=TCL_OK) return TCL_ERROR;
if (N==2) {
int to;
if (position(intr,P[1],m,&to)!=TCL_OK) return TCL_ERROR;
if (*from<0) *from = 0;
*len = to - *from + 1;
}else if (!strbegins("-l",Tcl_GetStringFromObj(P[1],0))) {
return rprintf(intr,"%!this should be -length: %{y}s",TCL_ERROR,P[1]);
}else {
if (Tcl_GetIntFromObj(intr,P[2],len)!=TCL_OK) return TCL_ERROR;
if (*from<0) {
*len += *from; *from = 0;
}
}
if (*len<=0) {
*from = 0; *len = 0;
}else {
if (from<0) {
*len -= *from; *from = 0;
}
if (*from+*len>m) {
*len = m-*from;
}
}
return TCL_OK;
}
static int byteslength(Obj obj) {
int n; Tcl_GetByteArrayFromObj(obj,&n); return n;
}
#ifdef NEED_MEMRCHR
static ptr memrchr(ptr s,int c,int n) {
bytes S = s; unsigned C = 0xFF&c;
while (n-->0) {
if (S[n]==C) return S+n;
}
return 0;
}
#endif
static int bytesCommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
Obj *P0 = P; int index;
static chars subcommands[] = {
"append","codes","compare","concatenate","difference",
"equal","first","index","last","length",
"printable","range","repeat","replace",
0
};
if (N<=1) {
Tcl_WrongNumArgs(intr,1,P0,"subcommand"); return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(intr,P[1],(CONST char**)subcommands,"subcommand",0,&index)!=TCL_OK) {
return TCL_ERROR;
}
N -= 2; P += 2;
switch (index) {
case 0: {
Obj var,val; int rc; bool copy,create; int i,totallength;
bytes dd,ss; int ndd,nss;
if (N<1) {
Tcl_WrongNumArgs(intr,2,P0,"variable ..."); return TCL_ERROR;
}
var = *P++; N--;
val = Tcl_ObjGetVar2(intr,var,0,0);
if (N==0) {
if (val) {
return TCL_OK;
}else {
return Tcl_ObjSetVar2(intr,var,0,Tcl_NewObj(),TCL_LEAVE_ERR_MSG) ? TCL_OK : TCL_ERROR;
}
}
copy = val && Tcl_IsShared(val);
create = val==0;
if (copy) {
val = incr(Tcl_DuplicateObj(val));
}else if (create) {
val = incr(Tcl_NewObj());
}
totallength = ndd = byteslength(val);
for (i=0; i<N; i++) totallength += byteslength(P[i]);
dd = Tcl_SetByteArrayLength(val,totallength);
for (i=0; i<N; i++) {
ss = Tcl_GetByteArrayFromObj(P[i],&nss);
memcpy(dd+ndd,ss,nss); ndd += nss;
}
if (copy || create) {
rc = Tcl_ObjSetVar2(intr,var,0,val,TCL_LEAVE_ERR_MSG) ? TCL_OK : TCL_ERROR;
decr(val);
}else
rc = TCL_OK;
return rc;
}
case 1: {
int m; bytes a; int from,len,i; char D[20];
if (N!=3 && N!=4) {
Tcl_WrongNumArgs(intr,2,P0,"binary from [-length] to"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
if (range(intr,N-1,P+1,m,&from,&len)!=TCL_OK) return TCL_ERROR;
Tcl_ResetResult(intr);
for (i=from; i<from+len; i++) {
sprintf(D,"%d",a[i]);
Tcl_AppendElement(intr,D);
}
return TCL_OK;
}
case 2: {
int m,n,l; bytes a,b; int cc;
if (N!=2 && N!=3) {
Tcl_WrongNumArgs(intr,2,P0,"binary binary [n]"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
b = Tcl_GetByteArrayFromObj(P[1],&n);
if (N==3) {
if (Tcl_GetIntFromObj(intr,P[2],&l)!=TCL_OK) return TCL_ERROR;
if (m>l) m = l;
if (n>l) n = l;
}
cc = m==n ? memcmp(a,b,m) : m-n;
Tcl_SetObjResult(intr,Tcl_NewIntObj(cc));
return TCL_OK;
}
case 3: {
int n,m; bytes b;
b = nheap(1,byte); m = 1; n = 0;
while (N-->0) {
int l; bytes a = Tcl_GetByteArrayFromObj(*P++,&l);
if (l==0) continue;
if (n+l>m) {
m = 2*(n+l); b = reheap(m,byte,b);
}
memcpy(b+n,a,l); n+= l;
}
Tcl_SetObjResult(intr,Tcl_NewByteArrayObj(b,n));
dispose(b);
return TCL_OK;
}
case 4: {
int m,n; bytes a,b; int i,starta=0,startb=0;
if (2>N || N>4) {
Tcl_WrongNumArgs(intr,2,P0,"binary [firststart [secondstart]]"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
b = Tcl_GetByteArrayFromObj(P[1],&n);
if (N>=3) {
if (Tcl_GetIntFromObj(intr,P[2],&starta)!=TCL_OK) return TCL_ERROR;
if (N==4) {
if (Tcl_GetIntFromObj(intr,P[3],&startb)!=TCL_OK) return TCL_ERROR;
}
}
for (i=0; i<m-starta && i<n-startb; i++) {
if (a[i+starta]!=b[i+startb]) break;
}
Tcl_SetObjResult(intr,Tcl_NewIntObj(i));
return TCL_OK;
}
case 5: {
int m,n,l; bytes a,b; int cc;
if (N!=2 && N!=3) {
Tcl_WrongNumArgs(intr,2,P0,"binary binary [n]"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
b = Tcl_GetByteArrayFromObj(P[1],&n);
if (N==3) {
if (Tcl_GetIntFromObj(intr,P[2],&l)!=TCL_OK) return TCL_ERROR;
if (m>l) m = l;
if (n>l) n = l;
}
cc = m==n ? memcmp(a,b,m) : m-n;
Tcl_SetObjResult(intr,Tcl_NewIntObj(!cc));
return TCL_OK;
}
case 6: {
int m; bytes a,p; int code; int start;
if (N!=2 && N!=3) {
Tcl_WrongNumArgs(intr,2,P0,"binary bytecode [startindex]"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
if (Tcl_GetIntFromObj(intr,P[1],&code)!=TCL_OK) return TCL_ERROR;
if (N==2) start = 0;
else if (position(intr,P[2],m,&start)!=TCL_OK) return TCL_ERROR;
p = memchr(a+start,code & 0xFF,m-start);
Tcl_SetObjResult(intr,Tcl_NewIntObj(p ? p-a : -1));
return TCL_OK;
}
case 7: {
int m; bytes a; int offset;
if (N!=2) {
Tcl_WrongNumArgs(intr,2,P0,"binary offset"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
if (position(intr,P[1],m,&offset)!=TCL_OK) return TCL_ERROR;
if (offset<0 || offset>=m) {
Tcl_ResetResult(intr);
}else {
Tcl_SetObjResult(intr,Tcl_NewIntObj(a[offset]));
}
return TCL_OK;
}
case 8: {
int m; bytes a,p; int code; int start;
if (N!=2 && N!=3) {
Tcl_WrongNumArgs(intr,2,P0,"binary bytecode [startindex]"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
if (Tcl_GetIntFromObj(intr,P[1],&code)!=TCL_OK) return TCL_ERROR;
if (N==2) start = m-1;
else if (position(intr,P[2],m,&start)!=TCL_OK) return TCL_ERROR;
p = memrchr(a,code & 0xFF,start+1);
Tcl_SetObjResult(intr,Tcl_NewIntObj(p ? p-a : -1));
return TCL_OK;
}
case 9: {
int m;
if (N!=1) {
Tcl_WrongNumArgs(intr,2,P0,"binary"); return TCL_ERROR;
}
Tcl_GetByteArrayFromObj(P[0],&m);
Tcl_SetObjResult(intr,Tcl_NewIntObj(m));
return TCL_OK;
}
case 10: {
bytes a; int m,i=0,n; char D[50];
if (N!=1) {
Tcl_WrongNumArgs(intr,2,P0,"binary"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
Tcl_ResetResult(intr);
while (i<m) {
n = 0;
while (i<m && ((32<=a[i] && a[i]<127) || a[i]=='\n')) {
n++; i++;
}
sprintf(D,"%d",n); Tcl_AppendElement(intr,D);
n = 0;
while (i<m && !((32<=a[i] && a[i]<127) || a[i]=='\n')) {
n++; i++;
}
sprintf(D,"%d",n); Tcl_AppendElement(intr,D);
}
return TCL_OK;
}
case 11: {
int m; bytes a; int from,len;
if (N!=3 && N!=4) {
Tcl_WrongNumArgs(intr,2,P0,"binary from [-length] to"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
if (range(intr,N-1,P+1,m,&from,&len)!=TCL_OK) return TCL_ERROR;
Tcl_SetObjResult(intr,Tcl_NewByteArrayObj(a+from,len));
return TCL_OK;
}
case 12: {
int m; bytes a; Obj result; bytes r; int n;
if (N!=2) {
Tcl_WrongNumArgs(intr,2,P0,"binary count"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
if (Tcl_GetIntFromObj(intr,P[1],&n)!=TCL_OK) return TCL_ERROR;
result = incr(Tcl_NewObj());
if (n*m>0) {
r = Tcl_SetByteArrayLength(result,n*m);
while (n-->0) {
memcpy(r,a,m); r+=m;
}
}
Tcl_SetObjResult(intr,result); decr(result);
return TCL_OK;
}
case 13: {
int m; bytes a; int n; bytes b; int from,len; Obj result; bytes r;
if (3>N || N>5) {
Tcl_WrongNumArgs(intr,2,P0,"binary from [-length] to [binary]"); return TCL_ERROR;
}
a = Tcl_GetByteArrayFromObj(P[0],&m);
if (N==5 || N==4 && !strieq("-length",Tcl_GetStringFromObj(P[2],0))) {
b = Tcl_GetByteArrayFromObj(P[N-1],&n); N--;
}else {
n = 0; b = 0;
}
if (range(intr,N-1,P+1,m,&from,&len)!=TCL_OK) return TCL_ERROR;
result = incr(Tcl_NewObj());
r = Tcl_SetByteArrayLength(result,m-len+n);
memcpy(r,a,from);
if (n) memcpy(r+from,b,n);
memcpy(r+from+n,a+from+len,m-from-len);
Tcl_SetObjResult(intr,result); decr(result);
return TCL_OK;
}
}
}