summary refs log tree commit diff stats
path: root/grus.go
blob: 15f3e0e17b8a82c8c2700c75f4a48086ba7c9b46 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package main

import (
	"bufio"
	"fmt"
	"os"

	"tildegit.org/andinus/grus/lexical"
)

func grus() {
	if len(os.Args) == 1 {
		fmt.Println("Usage: grus <word> <dictionaries>")
		os.Exit(1)
	}

	version := "v0.3.0"

	// Print version if first argument is version.
	if os.Args[1] == "version" {
		fmt.Printf("Grus %s\n", version)
		os.Exit(0)
	}

	// Define default environment variables.
	envVar := make(map[string]bool)
	envVar["GRUS_SEARCH_ALL"] = false
	envVar["GRUS_ANAGRAMS"] = true
	envVar["GRUS_STRICT_UNJUMBLE"] = false
	envVar["GRUS_PRINT_PATH"] = false

	// Check environment variables.
	for k, _ := range envVar {
		env := os.Getenv(k)
		if env == "false" ||
			env == "0" {
			envVar[k] = false
		} else if env == "true" ||
			env == "1" {
			envVar[k] = true
		}
	}

	// Print environment variables if first argument is env.
	if os.Args[1] == "env" {
		for k, v := range envVar {
			fmt.Printf("%s: %t\n", k, v)
		}
		os.Exit(0)
	}

	// Define default dictionaries.
	dicts := []string{
		"/usr/local/share/dict/words",
		"/usr/local/share/dict/web2",
		"/usr/share/dict/words",
		"/usr/share/dict/web2",
		"/usr/share/dict/special/4bsd",
		"/usr/share/dict/special/math",
	}

	// User has specified dictionaries, prepend them to dicts
	// list.
	if len(os.Args) >= 3 {
		dicts = append(os.Args[2:], dicts...)
	}

	// We use this to record if the word was unjumbled.
	unjumbled := false

	for k, dict := range dicts {
		if _, err := os.Stat(dict); err != nil &&
			!os.IsNotExist(err) {
			// Error is not nil & also it's not path
			// doesn't exist error. We do it this way to
			// avoid another level of indentation.
			panic(err)
		} else if err != nil &&
			os.IsNotExist(err) {
			// If file doesn't exist then continue with
			// next dictionary.
			continue
		}

		// Print path to dictionary if printPath is true.
		if envVar["GRUS_PRINT_PATH"] {
			if k != 0 {
				fmt.Println()
			}
			fmt.Println(dict)
		}

		file, err := os.Open(dict)
		panicOnErr(err)

		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			// Filter words by comparing length first &
			// run lexical.Sort on it only if the length
			// is equal.
			if len(scanner.Text()) == len(os.Args[1]) &&
				lexical.Sort(scanner.Text()) == lexical.Sort(os.Args[1]) {
				fmt.Println(scanner.Text())
				// If the user doesn't want anagrams
				// then exit the program.
				if !envVar["GRUS_ANAGRAMS"] {
					os.Exit(0)
				}
				unjumbled = true
			}
		}
		panicOnErr(scanner.Err())
		file.Close()

		// If the user has asked to strictly unjumble then we
		// cannot exit till it's unjumbled.
		if envVar["GRUS_STRICT_UNJUMBLE"] &&
			!unjumbled {
			// If user has asked to strictly unjumble & we
			// haven't done that yet & this is the last
			// dictionary then we've failed to unjumble it
			// & the program must exit with a non-zero
			// exit code.
			if k == len(dicts)-1 {
				os.Exit(1)
			}

			// Cannot exit, must search next dictionary.
			continue
		}

		// If user hasn't asked to search all dictionaries
		// then exit the program.
		if !envVar["GRUS_SEARCH_ALL"] {
			os.Exit(0)
		}

	}
}

func panicOnErr(err error) {
	if err != nil {
		panic(err)
	}
}