summaryrefslogtreecommitdiff
path: root/appl/cmd/sh/string.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/sh/string.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/sh/string.b')
-rw-r--r--appl/cmd/sh/string.b212
1 files changed, 212 insertions, 0 deletions
diff --git a/appl/cmd/sh/string.b b/appl/cmd/sh/string.b
new file mode 100644
index 00000000..b6d079e4
--- /dev/null
+++ b/appl/cmd/sh/string.b
@@ -0,0 +1,212 @@
+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;
+}