Backslash within double quotes #gu3

I’m stuck on Stage #GU3.

I’m unable to get the logic for this, I tried continuing after this else if, but then the 1st test case didn’t work. Some hint or tips would be appreciated.

if quoteChar != 0 && ch == '\\' {
			if i+1 < len(input) && rune(input[i+1]) == ch {
				continue
			} else if i+1 < len(input) && rune(input[i+1]) == '"' {
				word += string(input[i+1])
				i++
			}
		}

Here are my logs:

[tester::#GU3] Running ./your_program.sh
[your-program] $ echo "hello'test'\\'example"
[your-program] hello'test'\'example
[tester::#GU3] ✓ Received expected response
[your-program] $ echo "hello\"insidequotes"test\"
[your-program] hello"\insidequotes test"
[tester::#GU3] Output does not match expected value.
[tester::#GU3] Expected: "hello"insidequotestest""
[tester::#GU3] Received: "hello"\insidequotes test""
[your-program] $ 

Github repo: https://github.com/logan1o1/codecrafters-shell-go

And here’s a snippet of my code:

package main

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"slices"
	"strings"
	"unicode"
)

var builtins = []string{"exit", "echo", "type", "pwd"}

func FindPath(val string, paths []string) (string, bool) {
	for _, path := range paths {
		file := path + "/" + val
		if _, err := os.Stat(file); err == nil {
			return file, true
		}
	}
	return "", false
}

func InputParser(input string) (string, []string) {
	var word string
	var newArr []string
	var quoteChar rune
	var deferOpenFlush bool

	for i := 0; i < len(input); i++ {
		ch := rune(input[i])

		if quoteChar == 0 && ch == '\\' {
			if i+1 < len(input) {
				word += string(input[i+1])
				i++
			}
			continue
		}

		if ch == '\'' || ch == '"' {
			if quoteChar == 0 {
				if !deferOpenFlush && word != "" {
					newArr = append(newArr, word)
					word = ""
				}
				quoteChar = ch
				deferOpenFlush = false
			} else if quoteChar == ch {
				if i+1 < len(input) && rune(input[i+1]) == quoteChar {
					deferOpenFlush = true
				} else {
					newArr = append(newArr, word)
					word = ""
					deferOpenFlush = false
				}
				quoteChar = 0
			} else {
				word += string(ch)
			}
			continue
		}

		if quoteChar != 0 && ch == '\\' {
			if i+1 < len(input) && rune(input[i+1]) == ch {
				continue
			} else if i+1 < len(input) && rune(input[i+1]) == '"' {
				word += string(input[i+1])
				i++
			}
		}

		if quoteChar == 0 && unicode.IsSpace(ch) {
			if word != "" {
				newArr = append(newArr, word)
				word = ""
			}
			continue
		}

		word += string(ch)
	}

	if word != "" {
		newArr = append(newArr, word)
	}

	noSingles := strings.ReplaceAll(input, "'", "")
	noDoubles := strings.ReplaceAll(noSingles, `"`, "")
	output := noDoubles

	return output, newArr
}

func main() {

	for {
		fmt.Fprint(os.Stdout, "$ ")

		paths := strings.Split(os.Getenv("PATH"), ":")
		input, err := bufio.NewReader(os.Stdin).ReadString('\n')
		if err != nil {
			fmt.Fprintln(os.Stderr, "Error reading input: ", err)
			os.Exit(1)
		}

		cmdArr := strings.Fields(input)
		cmd := strings.TrimSpace(cmdArr[0])

		var args []string

		newInput, newArgsArr := InputParser(input)

		if strings.Contains(input, "'") || strings.Contains(input, `"`) || strings.Contains(input, `/`) || strings.Contains(input, `\`) {
			input = newInput
			args = newArgsArr[1:]
		} else if len(newArgsArr) == 0 {
			args = cmdArr[1:]
		} else {
			args = cmdArr[1:]
		}

		if strings.TrimSpace(input) == "exit 0" {
			break
		}

		switch cmd {
		case "echo":
			EchoCmd(args)
		case "type":
			TypeCmd(cmdArr, paths)
		case "pwd":
			Pwd()
		case "cd":
			Cd(args)
		default:
			filepath, exists := FindPath(cmd, paths)
			if exists && filepath != "" {
				CustomExeCmd(cmd, args)
			} else {
				fmt.Println(cmd + ": command not found")
			}
		}
	}

}

func EchoCmd(args []string) {
	output := strings.Join(args, " ")
	fmt.Println(output)
}

func TypeCmd(cmdArr []string, paths []string) {
	if len(cmdArr) == 1 {
		return
	}

	value := cmdArr[1]

	if slices.Contains(builtins, value) {
		fmt.Println(value + " is a shell builtin")
		return
	}

	if filePath, exists := FindPath(value, paths); exists {
		fmt.Println(value + " is " + filePath)
		return
	}

	fmt.Println(value + ": not found")
}

func CustomExeCmd(cmd string, args []string) {
	exc := exec.Command(cmd, args...)
	exc.Stdout = os.Stdout
	exc.Stderr = os.Stderr
	exc.Run()
}

func Pwd() {
	dir, err := os.Getwd()
	if err != nil {
		return
	}
	fmt.Println(dir)
}

func Cd(args []string) {
	path := strings.Join(args, "")
	homepath := os.Getenv("HOME")
	formatedPath := strings.ReplaceAll(path, "~", homepath)
	err := os.Chdir(formatedPath)
	if err != nil {
		fmt.Println("cd: " + path + ": No such file or directory")
	}
}

Solved, please close the post

1 Like

@logan1o1 Do you happen to remember what was wrong? Would love to see if we can improve the tester / instructions.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.