ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/sh/string.b/
implement Shellbuiltin;
include "sys.m";
sys: Sys;
include "draw.m";
include "sh.m";
sh: Sh;
Listnode, Context: import sh;
myself: Shellbuiltin;
include "string.m";
str: String;
initbuiltin(ctxt: ref Context, shmod: Sh): string
{
sys = load Sys Sys->PATH;
sh = shmod;
myself = load Shellbuiltin "$self";
if (myself == nil)
ctxt.fail("bad module", sys->sprint("string: cannot load self: %r"));
str = load String String->PATH;
if (str == nil)
ctxt.fail("bad module",
sys->sprint("string: cannot load %s: %r", String->PATH));
ctxt.addbuiltin("prefix", myself);
ctxt.addbuiltin("in", myself);
names := array[] of {
"splitl", "splitr", "drop", "take", "splitstrl", "splitstrr",
"tolower", "toupper", "len", "alen", "slice", "fields",
"padl", "padr",
};
for (i := 0; i < len names; i++)
ctxt.addsbuiltin(names[i], myself);
return nil;
}
whatis(nil: ref Sh->Context, nil: Sh, nil: string, nil: int): string
{
return nil;
}
getself(): Shellbuiltin
{
return myself;
}
runbuiltin(ctxt: ref Context, nil: Sh,
argv: list of ref Listnode, nil: int): string
{
case (hd argv).word {
"prefix" =>
(a, b) := earg2("prefix", ctxt, argv);
if (!str->prefix(a, b))
return "false";
"in" =>
(a, b) := earg2("in", ctxt, argv);
if (a == nil || !str->in(a[0], b))
return "false";
}
return nil;
}
runsbuiltin(ctxt: ref Context, nil: Sh,
argv: list of ref Listnode): list of ref Listnode
{
name := (hd argv).word;
case name {
"splitl" =>
(a, b) := earg2("splitl", ctxt, argv);
return mk2(str->splitl(a, b));
"splitr" =>
(a, b) := earg2("splitr", ctxt, argv);
return mk2(str->splitr(a, b));
"drop" =>
(a, b) := earg2("drop", ctxt, argv);
return mk1(str->drop(a, b));
"take" =>
(a, b) := earg2("take", ctxt, argv);
return mk1(str->take(a, b));
"splitstrl" =>
(a, b) := earg2("splitstrl", ctxt, argv);
return mk2(str->splitstrl(a, b));
"splitstrr" =>
(a, b) := earg2("splitstrr", ctxt, argv);
return mk2(str->splitstrr(a, b));
"tolower" =>
return mk1(str->tolower(earg1("tolower", ctxt, argv)));
"toupper" =>
return mk1(str->toupper(earg1("tolower", ctxt, argv)));
"len" =>
return mk1(string len earg1("len", ctxt, argv));
"alen" =>
return mk1(string len array of byte earg1("alen", ctxt, argv));
"slice" =>
return sbuiltin_slice(ctxt, argv);
"fields" =>
return sbuiltin_fields(ctxt, argv);
"padl" =>
return sbuiltin_pad(ctxt, argv, -1);
"padr" =>
return sbuiltin_pad(ctxt, argv, 1);
}
return nil;
}
sbuiltin_pad(ctxt: ref Context, argv: list of ref Listnode, dir: int): list of ref Listnode
{
if (tl argv == nil || !isnum((hd tl argv).word))
ctxt.fail("usage", "usage: " + (hd argv).word + " n [arg...]");
argv = tl argv;
n := int (hd argv).word * dir;
s := "";
for (argv = tl argv; argv != nil; argv = tl argv) {
s += word(hd argv);
if (tl argv != nil)
s[len s] = ' ';
}
if (n != 0)
s = sys->sprint("%*s", n, s);
return ref Listnode(nil, s) :: nil;
}
sbuiltin_fields(ctxt: ref Context, argv: list of ref Listnode): list of ref Listnode
{
argv = tl argv;
if (len argv != 2)
ctxt.fail("usage", "usage: fields cl s");
cl := word(hd argv);
s := word(hd tl argv);
r: list of string;
n := 0;
for (i := 0; i < len s; i++) {
if (str->in(s[i], cl)) {
r = s[n:i] :: r;
n = i + 1;
}
}
r = s[n:i] :: r;
rl: list of ref Listnode;
for (; r != nil; r = tl r)
rl = ref Listnode(nil, hd r) :: rl;
return rl;
}
sbuiltin_slice(ctxt: ref Context, argv: list of ref Listnode): list of ref Listnode
{
argv = tl argv;
if (len argv != 3 || !isnum((hd argv).word) ||
(hd tl argv).word != "end" && !isnum((hd tl argv).word))
ctxt.fail("usage", "usage: slice start end arg");
n1 := int (hd argv).word;
n2: int;
s := word(hd tl tl argv);
r := "";
if ((hd tl argv).word == "end")
n2 = len s;
else
n2 = int (hd tl argv).word;
if (n2 > len s)
n2 = len s;
if (n1 > len s)
n1 = len s;
if (n2 > n1)
r = s[n1:n2];
return mk1(r);
}
earg2(cmd: string, ctxt: ref Context, argv: list of ref Listnode): (string, string)
{
argv = tl argv;
if (len argv != 2)
ctxt.fail("usage", "usage: " + cmd + " arg1 arg2");
return (word(hd argv), word(hd tl argv));
}
earg1(cmd: string, ctxt: ref Context, argv: list of ref Listnode): string
{
if (len argv != 2)
ctxt.fail("usage", "usage: " + cmd + " arg");
return word(hd tl argv);
}
mk2(x: (string, string)): list of ref Listnode
{
(a, b) := x;
return ref Listnode(nil, a) :: ref Listnode(nil, b) :: nil;
}
mk1(x: string): list of ref Listnode
{
return ref Listnode(nil, x) :: nil;
}
isnum(s: string): int
{
for (i := 0; i < len s; i++)
if (s[i] > '9' || s[i] < '0')
return 0;
return 1;
}
word(n: ref Listnode): string
{
if (n.word != nil)
return n.word;
if (n.cmd != nil)
n.word = sh->cmd2string(n.cmd);
return n.word;
}