1*37da2899SCharles.Forsythimplement Shellbuiltin; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsythinclude "sys.m"; 4*37da2899SCharles.Forsyth sys: Sys; 5*37da2899SCharles.Forsythinclude "draw.m"; 6*37da2899SCharles.Forsythinclude "sh.m"; 7*37da2899SCharles.Forsyth sh: Sh; 8*37da2899SCharles.Forsyth Listnode, Context: import sh; 9*37da2899SCharles.Forsyth myself: Shellbuiltin; 10*37da2899SCharles.Forsythinclude "string.m"; 11*37da2899SCharles.Forsyth str: String; 12*37da2899SCharles.Forsyth 13*37da2899SCharles.Forsythinitbuiltin(ctxt: ref Context, shmod: Sh): string 14*37da2899SCharles.Forsyth{ 15*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 16*37da2899SCharles.Forsyth sh = shmod; 17*37da2899SCharles.Forsyth myself = load Shellbuiltin "$self"; 18*37da2899SCharles.Forsyth if (myself == nil) 19*37da2899SCharles.Forsyth ctxt.fail("bad module", sys->sprint("string: cannot load self: %r")); 20*37da2899SCharles.Forsyth str = load String String->PATH; 21*37da2899SCharles.Forsyth if (str == nil) 22*37da2899SCharles.Forsyth ctxt.fail("bad module", 23*37da2899SCharles.Forsyth sys->sprint("string: cannot load %s: %r", String->PATH)); 24*37da2899SCharles.Forsyth ctxt.addbuiltin("prefix", myself); 25*37da2899SCharles.Forsyth ctxt.addbuiltin("in", myself); 26*37da2899SCharles.Forsyth names := array[] of { 27*37da2899SCharles.Forsyth "splitl", "splitr", "drop", "take", "splitstrl", "splitstrr", 28*37da2899SCharles.Forsyth "tolower", "toupper", "len", "alen", "slice", "fields", 29*37da2899SCharles.Forsyth "padl", "padr", 30*37da2899SCharles.Forsyth }; 31*37da2899SCharles.Forsyth for (i := 0; i < len names; i++) 32*37da2899SCharles.Forsyth ctxt.addsbuiltin(names[i], myself); 33*37da2899SCharles.Forsyth return nil; 34*37da2899SCharles.Forsyth} 35*37da2899SCharles.Forsyth 36*37da2899SCharles.Forsythwhatis(nil: ref Sh->Context, nil: Sh, nil: string, nil: int): string 37*37da2899SCharles.Forsyth{ 38*37da2899SCharles.Forsyth return nil; 39*37da2899SCharles.Forsyth} 40*37da2899SCharles.Forsyth 41*37da2899SCharles.Forsythgetself(): Shellbuiltin 42*37da2899SCharles.Forsyth{ 43*37da2899SCharles.Forsyth return myself; 44*37da2899SCharles.Forsyth} 45*37da2899SCharles.Forsyth 46*37da2899SCharles.Forsythrunbuiltin(ctxt: ref Context, nil: Sh, 47*37da2899SCharles.Forsyth argv: list of ref Listnode, nil: int): string 48*37da2899SCharles.Forsyth{ 49*37da2899SCharles.Forsyth case (hd argv).word { 50*37da2899SCharles.Forsyth "prefix" => 51*37da2899SCharles.Forsyth (a, b) := earg2("prefix", ctxt, argv); 52*37da2899SCharles.Forsyth if (!str->prefix(a, b)) 53*37da2899SCharles.Forsyth return "false"; 54*37da2899SCharles.Forsyth "in" => 55*37da2899SCharles.Forsyth (a, b) := earg2("in", ctxt, argv); 56*37da2899SCharles.Forsyth if (a == nil || !str->in(a[0], b)) 57*37da2899SCharles.Forsyth return "false"; 58*37da2899SCharles.Forsyth } 59*37da2899SCharles.Forsyth return nil; 60*37da2899SCharles.Forsyth} 61*37da2899SCharles.Forsyth 62*37da2899SCharles.Forsythrunsbuiltin(ctxt: ref Context, nil: Sh, 63*37da2899SCharles.Forsyth argv: list of ref Listnode): list of ref Listnode 64*37da2899SCharles.Forsyth{ 65*37da2899SCharles.Forsyth name := (hd argv).word; 66*37da2899SCharles.Forsyth case name { 67*37da2899SCharles.Forsyth "splitl" => 68*37da2899SCharles.Forsyth (a, b) := earg2("splitl", ctxt, argv); 69*37da2899SCharles.Forsyth return mk2(str->splitl(a, b)); 70*37da2899SCharles.Forsyth "splitr" => 71*37da2899SCharles.Forsyth (a, b) := earg2("splitr", ctxt, argv); 72*37da2899SCharles.Forsyth return mk2(str->splitr(a, b)); 73*37da2899SCharles.Forsyth "drop" => 74*37da2899SCharles.Forsyth (a, b) := earg2("drop", ctxt, argv); 75*37da2899SCharles.Forsyth return mk1(str->drop(a, b)); 76*37da2899SCharles.Forsyth "take" => 77*37da2899SCharles.Forsyth (a, b) := earg2("take", ctxt, argv); 78*37da2899SCharles.Forsyth return mk1(str->take(a, b)); 79*37da2899SCharles.Forsyth "splitstrl" => 80*37da2899SCharles.Forsyth (a, b) := earg2("splitstrl", ctxt, argv); 81*37da2899SCharles.Forsyth return mk2(str->splitstrl(a, b)); 82*37da2899SCharles.Forsyth "splitstrr" => 83*37da2899SCharles.Forsyth (a, b) := earg2("splitstrr", ctxt, argv); 84*37da2899SCharles.Forsyth return mk2(str->splitstrr(a, b)); 85*37da2899SCharles.Forsyth "tolower" => 86*37da2899SCharles.Forsyth return mk1(str->tolower(earg1("tolower", ctxt, argv))); 87*37da2899SCharles.Forsyth "toupper" => 88*37da2899SCharles.Forsyth return mk1(str->toupper(earg1("tolower", ctxt, argv))); 89*37da2899SCharles.Forsyth "len" => 90*37da2899SCharles.Forsyth return mk1(string len earg1("len", ctxt, argv)); 91*37da2899SCharles.Forsyth "alen" => 92*37da2899SCharles.Forsyth return mk1(string len array of byte earg1("alen", ctxt, argv)); 93*37da2899SCharles.Forsyth "slice" => 94*37da2899SCharles.Forsyth return sbuiltin_slice(ctxt, argv); 95*37da2899SCharles.Forsyth "fields" => 96*37da2899SCharles.Forsyth return sbuiltin_fields(ctxt, argv); 97*37da2899SCharles.Forsyth "padl" => 98*37da2899SCharles.Forsyth return sbuiltin_pad(ctxt, argv, -1); 99*37da2899SCharles.Forsyth "padr" => 100*37da2899SCharles.Forsyth return sbuiltin_pad(ctxt, argv, 1); 101*37da2899SCharles.Forsyth } 102*37da2899SCharles.Forsyth return nil; 103*37da2899SCharles.Forsyth} 104*37da2899SCharles.Forsyth 105*37da2899SCharles.Forsythsbuiltin_pad(ctxt: ref Context, argv: list of ref Listnode, dir: int): list of ref Listnode 106*37da2899SCharles.Forsyth{ 107*37da2899SCharles.Forsyth if (tl argv == nil || !isnum((hd tl argv).word)) 108*37da2899SCharles.Forsyth ctxt.fail("usage", "usage: " + (hd argv).word + " n [arg...]"); 109*37da2899SCharles.Forsyth 110*37da2899SCharles.Forsyth argv = tl argv; 111*37da2899SCharles.Forsyth n := int (hd argv).word * dir; 112*37da2899SCharles.Forsyth s := ""; 113*37da2899SCharles.Forsyth for (argv = tl argv; argv != nil; argv = tl argv) { 114*37da2899SCharles.Forsyth s += word(hd argv); 115*37da2899SCharles.Forsyth if (tl argv != nil) 116*37da2899SCharles.Forsyth s[len s] = ' '; 117*37da2899SCharles.Forsyth } 118*37da2899SCharles.Forsyth if (n != 0) 119*37da2899SCharles.Forsyth s = sys->sprint("%*s", n, s); 120*37da2899SCharles.Forsyth return ref Listnode(nil, s) :: nil; 121*37da2899SCharles.Forsyth} 122*37da2899SCharles.Forsyth 123*37da2899SCharles.Forsythsbuiltin_fields(ctxt: ref Context, argv: list of ref Listnode): list of ref Listnode 124*37da2899SCharles.Forsyth{ 125*37da2899SCharles.Forsyth argv = tl argv; 126*37da2899SCharles.Forsyth if (len argv != 2) 127*37da2899SCharles.Forsyth ctxt.fail("usage", "usage: fields cl s"); 128*37da2899SCharles.Forsyth cl := word(hd argv); 129*37da2899SCharles.Forsyth s := word(hd tl argv); 130*37da2899SCharles.Forsyth 131*37da2899SCharles.Forsyth r: list of string; 132*37da2899SCharles.Forsyth 133*37da2899SCharles.Forsyth n := 0; 134*37da2899SCharles.Forsyth for (i := 0; i < len s; i++) { 135*37da2899SCharles.Forsyth if (str->in(s[i], cl)) { 136*37da2899SCharles.Forsyth r = s[n:i] :: r; 137*37da2899SCharles.Forsyth n = i + 1; 138*37da2899SCharles.Forsyth } 139*37da2899SCharles.Forsyth } 140*37da2899SCharles.Forsyth r = s[n:i] :: r; 141*37da2899SCharles.Forsyth rl: list of ref Listnode; 142*37da2899SCharles.Forsyth for (; r != nil; r = tl r) 143*37da2899SCharles.Forsyth rl = ref Listnode(nil, hd r) :: rl; 144*37da2899SCharles.Forsyth return rl; 145*37da2899SCharles.Forsyth} 146*37da2899SCharles.Forsyth 147*37da2899SCharles.Forsyth 148*37da2899SCharles.Forsythsbuiltin_slice(ctxt: ref Context, argv: list of ref Listnode): list of ref Listnode 149*37da2899SCharles.Forsyth{ 150*37da2899SCharles.Forsyth argv = tl argv; 151*37da2899SCharles.Forsyth if (len argv != 3 || !isnum((hd argv).word) || 152*37da2899SCharles.Forsyth (hd tl argv).word != "end" && !isnum((hd tl argv).word)) 153*37da2899SCharles.Forsyth ctxt.fail("usage", "usage: slice start end arg"); 154*37da2899SCharles.Forsyth n1 := int (hd argv).word; 155*37da2899SCharles.Forsyth n2: int; 156*37da2899SCharles.Forsyth s := word(hd tl tl argv); 157*37da2899SCharles.Forsyth r := ""; 158*37da2899SCharles.Forsyth if ((hd tl argv).word == "end") 159*37da2899SCharles.Forsyth n2 = len s; 160*37da2899SCharles.Forsyth else 161*37da2899SCharles.Forsyth n2 = int (hd tl argv).word; 162*37da2899SCharles.Forsyth if (n2 > len s) 163*37da2899SCharles.Forsyth n2 = len s; 164*37da2899SCharles.Forsyth if (n1 > len s) 165*37da2899SCharles.Forsyth n1 = len s; 166*37da2899SCharles.Forsyth if (n2 > n1) 167*37da2899SCharles.Forsyth r = s[n1:n2]; 168*37da2899SCharles.Forsyth return mk1(r); 169*37da2899SCharles.Forsyth} 170*37da2899SCharles.Forsyth 171*37da2899SCharles.Forsythearg2(cmd: string, ctxt: ref Context, argv: list of ref Listnode): (string, string) 172*37da2899SCharles.Forsyth{ 173*37da2899SCharles.Forsyth argv = tl argv; 174*37da2899SCharles.Forsyth if (len argv != 2) 175*37da2899SCharles.Forsyth ctxt.fail("usage", "usage: " + cmd + " arg1 arg2"); 176*37da2899SCharles.Forsyth return (word(hd argv), word(hd tl argv)); 177*37da2899SCharles.Forsyth} 178*37da2899SCharles.Forsyth 179*37da2899SCharles.Forsythearg1(cmd: string, ctxt: ref Context, argv: list of ref Listnode): string 180*37da2899SCharles.Forsyth{ 181*37da2899SCharles.Forsyth if (len argv != 2) 182*37da2899SCharles.Forsyth ctxt.fail("usage", "usage: " + cmd + " arg"); 183*37da2899SCharles.Forsyth return word(hd tl argv); 184*37da2899SCharles.Forsyth} 185*37da2899SCharles.Forsyth 186*37da2899SCharles.Forsythmk2(x: (string, string)): list of ref Listnode 187*37da2899SCharles.Forsyth{ 188*37da2899SCharles.Forsyth (a, b) := x; 189*37da2899SCharles.Forsyth return ref Listnode(nil, a) :: ref Listnode(nil, b) :: nil; 190*37da2899SCharles.Forsyth} 191*37da2899SCharles.Forsyth 192*37da2899SCharles.Forsythmk1(x: string): list of ref Listnode 193*37da2899SCharles.Forsyth{ 194*37da2899SCharles.Forsyth return ref Listnode(nil, x) :: nil; 195*37da2899SCharles.Forsyth} 196*37da2899SCharles.Forsyth 197*37da2899SCharles.Forsythisnum(s: string): int 198*37da2899SCharles.Forsyth{ 199*37da2899SCharles.Forsyth for (i := 0; i < len s; i++) 200*37da2899SCharles.Forsyth if (s[i] > '9' || s[i] < '0') 201*37da2899SCharles.Forsyth return 0; 202*37da2899SCharles.Forsyth return 1; 203*37da2899SCharles.Forsyth} 204*37da2899SCharles.Forsyth 205*37da2899SCharles.Forsythword(n: ref Listnode): string 206*37da2899SCharles.Forsyth{ 207*37da2899SCharles.Forsyth if (n.word != nil) 208*37da2899SCharles.Forsyth return n.word; 209*37da2899SCharles.Forsyth if (n.cmd != nil) 210*37da2899SCharles.Forsyth n.word = sh->cmd2string(n.cmd); 211*37da2899SCharles.Forsyth return n.word; 212*37da2899SCharles.Forsyth} 213