diff --git a/src/fsh.nim b/src/fsh.nim index a2bcc80..417cd32 100644 --- a/src/fsh.nim +++ b/src/fsh.nim @@ -7,6 +7,7 @@ import streams import osproc import strtabs import os +import strutils # globals var shellVariables = newStringTable(modeCaseSensitive) @@ -16,6 +17,13 @@ var envVariables = newStringTable(modeCaseSensitive) for k, v in envPairs(): envVariables[k]=v +# list of builtin commands +let builtins: array[3, string] = [ +"set", +"setenv", +"echo", +] + # forward declarations proc eval(cmd: string): string proc substitute(strm: Stream, delim = ";\p"): string @@ -185,11 +193,38 @@ proc parseCommand(cmd: string): seq[string] = discard strm.skipSpaces() else: newitem.add(c) +# runBuiltin runs a shell builtin +proc runBuiltin(builtin: string, args: openArray[string]): string = + case builtin: + of "set": + if args.len < 2: + raise newException(Exception, "Set: not enough arguments provided") + shellVariables[args[0]] = args[1..^1].join(" ") + return "" + of "setenv": + if args.len < 2: + raise newException(Exception, "setenv: Not enough arguments provided") + try: + envVariables[args[0]] = args[1..^1].join(":") + putEnv(args[0], args[1..^1].join(":")) + except OSError as e: + raise newException(Exception, "setenv: " & e.msg) + return "" + of "echo": + if args[0] == "-n": + return args[1..^1].join(" ") + return args.join(" ") & "\p" + else: + raise newException(Exception, "Fsh: No such builtin implemented") + # executes executes the command. For now it involves catting the command and printing it proc execute(cmd: string): int = let parsed = cmd.parseCommand let progname = parsed[0] let args = parsed[1..parsed.high] + if progname in builtins: + stdout.write(runBuiltin(progname, args)) + return 0 let ps = startProcess(progname, args=args, options={poUsePath, poParentStreams}) result = ps.waitForExit ps.close @@ -199,6 +234,8 @@ proc eval(cmd: string): string = let parsed = cmd.parseCommand let progname=parsed[0] let args = parsed[1..parsed.high] + if progname in builtins: + return runBuiltin(progname, args) let ps = startProcess(progname, args=args, options={poUsePath}) result=ps.outputStream.readAll ps.close