ref: fa9f4c5c6852ce467644f610e77504664cb86af4
dir: /appl/lib/tcl_list.b/
implement TclLib;
include "sys.m";
sys: Sys;
include "draw.m";
include "tk.m";
include "bufio.m";
bufmod : Bufio;
Iobuf : import bufmod;
include "string.m";
str : String;
include "tcl.m";
include "tcllib.m";
include "utils.m";
utils : Tcl_Utils;
error : int;
DEF,DEC,INT : con iota;
valid_commands:= array[] of {
"concat" ,
"join" ,
"lindex" ,
"linsert" ,
"list" ,
"llength" ,
"lrange" ,
"lreplace" ,
"lsearch" ,
"lsort" ,
"split"
};
about() : array of string {
return valid_commands;
}
exec(tcl : ref Tcl_Core->TclData,argv : array of string) : (int,string) {
if (tcl.context==nil);
str = load String String->PATH;
sys = load Sys Sys->PATH;
utils = load Tcl_Utils Tcl_Utils->PATH;
if (str==nil || utils==nil)
return (1,"Can't load modules\n");
case argv[0] {
"concat" =>
return (error,do_concat(argv,0));
"join" =>
return (error,do_join(argv));
"lindex" =>
return (error,do_lindex(argv));
"linsert" =>
return (error,do_linsert(argv));
"list" =>
return (error,do_concat(argv,1));
"llength" =>
return (error,do_llength(argv));
"lrange" =>
return (error,do_lrange(argv));
"lreplace" =>
return (error,do_lreplace(argv));
"lsearch" =>
return (error,do_lsearch(argv));
"lsort" =>
return (error,do_lsort(argv));
"split" =>
return (error,do_split(argv));
}
return (1,nil);
}
spaces(s : string) : int{
if (s==nil) return 1;
for(i:=0;i<len s;i++)
if (s[i]==' ' || s[i]=='\t') return 1;
return 0;
}
sort(a: array of string, key: int): array of string {
m: int;
n := len a;
for(m = n; m > 1; ) {
if(m < 5)
m = 1;
else
m = (5*m-1)/11;
for(i := n-m-1; i >= 0; i--) {
tmp := a[i];
for(j := i+m; j <= n-1 && greater(tmp, a[j], key); j += m)
a[j-m] = a[j];
a[j-m] = tmp;
}
}
return a;
}
greater(x, y: string, sortkey: int): int {
case (sortkey) {
DEF => return(x > y);
DEC => return(x < y);
INT => return(int x > int y);
}
return 0;
}
# from here on are the commands in alphabetical order...
# turns an array into a string with spaces between the elements.
# in braces is non-zero, the elements will be enclosed in braces.
do_concat(argv : array of string, braces : int) : string {
retval :string;
retval=nil;
for(i:=1;i<len argv;i++){
flag:=0;
if (spaces(argv[i])) flag=1;
if (braces && flag) retval[len retval]='{';
retval += argv[i];
if (braces && flag) retval[len retval]='}';
retval[len retval]=' ';
}
if (retval!=nil)
retval=retval[0:len retval-1];
return retval;
}
do_join(argv : array of string) : string {
retval : string;
if (len argv ==1 || len argv >3)
return notify(1,"join list ?joinString?");
if (len argv == 2)
return argv[1];
if (argv[1]==nil) return nil;
arr := utils->break_it(argv[1]);
for (i:=0;i<len arr;i++){
retval+=arr[i];
if (i!=len arr -1)
retval+=argv[2];
}
return retval;
}
do_lindex(argv : array of string) : string {
if (len argv != 3)
return notify(1,"lindex list index");
(num,rest):=str->toint(argv[2],10);
if (rest!=nil)
return notify(2,argv[2]);
arr:=utils->break_it(argv[1]);
if (num>=len arr)
return nil;
return arr[num];
}
do_linsert(argv : array of string) : string {
if (len argv < 4){
return notify(1,
"linsert list index element ?element ...?");
}
(num,rest):=str->toint(argv[2],10);
if (rest!=nil)
return notify(2,argv[2]);
arr:=utils->break_it(argv[1]);
narr := array[len arr + len argv - 2] of string;
narr[0]="do_concat";
if (num==0){
narr[1:]=argv[3:];
narr[len argv -2:]=arr[0:];
}else if (num>= len arr){
narr[1:]=arr[0:];
narr[len arr+1:]=argv[3:];
}else{
narr[1:]=arr[0:num];
narr[num+1:]=argv[3:];
narr[num+len argv -2:]=arr[num:];
}
return do_concat(narr,1);
}
do_llength(argv : array of string) : string {
if (len argv !=2){
return notify(1,"llength list");
}
arr:=utils->break_it(argv[1]);
return string len arr;
}
do_lrange(argv :array of string) : string {
beg,end : int;
rest : string;
if (len argv != 4)
return notify(1,"lrange list first last");
(beg,rest)=str->toint(argv[2],10);
if (rest!=nil)
return notify(2,argv[2]);
(end,rest)=str->toint(argv[3],10);
if (rest!=nil)
return notify(2,argv[3]);
if (beg <0) beg=0;
if (end < 0) return nil;
if (beg > end) return nil;
arr:=utils->break_it(argv[1]);
if (beg>len arr) return nil;
narr:=array[end-beg+2] of string;
narr[0]="do_concat";
narr[1:]=arr[beg:end+1];
return do_concat(narr,1);
}
do_lreplace(argv : array of string) : string {
beg,end : int;
rest : string;
if (len argv < 3)
return notify(1,"lreplace list "+
"first last ?element element ...?");
arr:=utils->break_it(argv[1]);
(beg,rest)=str->toint(argv[2],10);
if (rest!=nil)
return notify(2,argv[2]);
(end,rest)=str->toint(argv[3],10);
if (rest!=nil)
return notify(2,argv[3]);
if (beg <0) beg=0;
if (end < 0) return nil;
if (beg > end)
return notify(0,
"first index must not be greater than second");
if (beg>len arr)
return notify(1,
"list doesn't contain element "+string beg);
narr:=array[len arr-(end-beg+1)+len argv - 3] of string;
narr[1:]=arr[0:beg];
narr[beg+1:]=argv[4:];
narr[beg+1+len argv-4:]=arr[end+1:];
narr[0]="do_concat";
return do_concat(narr,1);
}
do_lsearch(argv : array of string) : string {
if (len argv!=3)
return notify(1,"lsearch ?mode? list pattern");
arr:=utils->break_it(argv[1]);
for(i:=0;i<len arr;i++)
if (arr[i]==argv[2])
return string i;
return "-1";
}
do_lsort(argv : array of string) : string {
lis : array of string;
key : int;
key=DEF;
if (len argv == 1)
return notify(1,"lsort ?-ascii? ?-integer? ?-real?"+
" ?-increasing? ?-decreasing?"+
" ?-command string? list");
for(i:=1;i<len argv;i++)
if (argv[i][0]=='-')
case argv[i]{
"-decreasing" =>
key = DEC;
* =>
if (len argv != i+1)
return notify(0,sys->sprint(
"bad switch \"%s\": must be"+
" -ascii, -integer, -real, "+
"-increasing -decreasing, or"+
" -command" ,argv[i]));
}
lis=utils->break_it(argv[len argv-1]);
arr:=sort(lis,key);
narr:= array[len arr+1] of string;
narr[0]="list";
narr[1:]=arr[0:];
return do_concat(narr,1);
}
do_split(argv : array of string) : string {
arr := array[20] of string;
narr : array of string;
if (len argv ==1 || len argv>3)
return notify(1,"split string ?splitChars?");
if (len argv == 2)
return argv[1];
s:=argv[1];
if (s==nil) return nil;
if (argv[2]==nil){
arr=array[len s+1] of string;
for(i:=0;i<len s;i++)
arr[i+1][len arr[i+1]]=s[i];
arr[0]="do_concat";
return do_concat(arr,1);
}
i:=1;
while(s!=nil){
(piece,rest):=str->splitl(s,argv[2]);
arr[i]=piece;
if (len rest>1)
s=rest[1:];
if (len rest==1)
s=nil;
i++;
if (i==len arr){
narr=array[i+10] of string;
narr[0:]=arr[0:];
arr=array[i+10] of string;
arr=narr;
}
}
narr = array[i] of string;
arr[0]="do_concat";
narr = arr[0:i+1];
return do_concat(narr,1);
}
notify(num : int,s : string) : string {
error=1;
case num{
1 =>
return sys->sprint(
"wrong # args: should be \"%s\"",s);
2 =>
return sys->sprint(
"expected integer but got \"%s\"",s);
* =>
return s;
}
}