summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndinus <andinus@nand.sh>2020-04-08 04:31:21 +0530
committerAndinus <andinus@nand.sh>2020-04-08 04:37:48 +0530
commitfa68976a3e7adb8c2c3327c6afc44fef24297337 (patch)
treebe78b3586c60a47845f2c334478628a86fda1d14
parenta3ede2f5edd006affda8ab386dee3fd44d61c473 (diff)
downloadgrus-fa68976a3e7adb8c2c3327c6afc44fef24297337.tar.gz
Initial rewrite of grus
-rw-r--r--README.org40
-rw-r--r--go.sum2
-rw-r--r--grus.go106
-rw-r--r--main_openbsd.go44
-rw-r--r--main_other.go7
5 files changed, 193 insertions, 6 deletions
diff --git a/README.org b/README.org
index 2aad5e9..859005d 100644
--- a/README.org
+++ b/README.org
@@ -10,12 +10,40 @@ Grus is a simple word unjumbler written in Go.
 | GitHub (Mirror) | [[https://github.com/andinus/grus][Grus - GitHub]]  |
 
 *Tested on*:
-- OpenBSD 6.6 (with /unveil/)
+- OpenBSD 6.6 (with /pledge/ & /unveil/)
 
-* Working
-- Grus takes a word as input from the user
-- Input is ordered in [[https://wikipedia.org/wiki/Lexicographical_order][lexical order]]
-- Ordered input is searched in dictionary
+* Documentation
+Grus stops the search as soon as it unjumbles the word, so no anagrams are
+returned & maybe all dictionaries were not searched. However, this behaviour can
+be changed with two environment variables documented below.
+
+*Note*: If grus couldn't unjumble the word with first dictionary then it'll search
+in next dictionary, search stops once the word gets unjumbled.
+
+| Environment variable | Explanation                | Non-default values |
+|----------------------+----------------------------+--------------------|
+| =GRUS_SEARCH_ALL=      | Search in all dictionaries | 1 / true           |
+| =GRUS_ANAGRAMS=        | Print all anagrams         | 1 / true           |
+** Examples
+#+BEGIN_SRC sh
+# unjumble word
+grus word
+
+# print all anagrams
+GRUS_ANAGRAMS=true grus word
+
+# search for word in all dictionaries
+GRUS_SEARCH_ALL=true grus word
+
+# search for word in custom dictionaries too
+grus word /path/to/dict1 /path/to/dict2
+
+# search for word in all dictionaries
+GRUS_SEARCH_ALL=1 grus word /path/to/dict1 /path/to/dict2
+
+# search for word in all dictionaries & print all anagrams
+GRUS_SEARCH_ALL=1 GRUS_ANAGRAMS=1 grus word
+#+END_SRC
 * History
 Initial version of Grus was just a simple shell script that used the slowest
 method of unjumbling words, it checked every permutation of the word with all
@@ -113,5 +141,5 @@ database.
 
 This was true till v0.1.0, v0.2.0 was rewritten & it dropped the use of database
 or any form of pre-parsing the dictionary. Instead it would look through each
-line of dictionary & unjumble the word, while this is a lot slower than previous
+line of dictionary & unjumble the word, while this may be slower than previous
 version but this is simpler.
diff --git a/go.sum b/go.sum
index dbd60ff..8d3b70d 100644
--- a/go.sum
+++ b/go.sum
@@ -3,3 +3,5 @@ golang.org/x/sys v0.0.0-20200406113430-c6e801f48ba2 h1:Z9pPywZscwuw0ijrLEbTzW9lp
 golang.org/x/sys v0.0.0-20200406113430-c6e801f48ba2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 tildegit.org/andinus/lynx v0.1.0 h1:7YjyF8h7MBGKRgQZT0j0I3uHRPf3mI2GMiDujXVlLS0=
 tildegit.org/andinus/lynx v0.1.0/go.mod h1:/PCNkKwfJ7pb6ziHa76a4gYp1R9S1Ro4ANjQwzSpBIk=
+tildegit.org/andinus/lynx v0.2.0 h1:cBoAWqC/osZJE4VPdB0HhIEpMIC4A4eI9nEbHR/9Qvk=
+tildegit.org/andinus/lynx v0.2.0/go.mod h1:/PCNkKwfJ7pb6ziHa76a4gYp1R9S1Ro4ANjQwzSpBIk=
diff --git a/grus.go b/grus.go
new file mode 100644
index 0000000..d4a63ad
--- /dev/null
+++ b/grus.go
@@ -0,0 +1,106 @@
+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.2.0"
+
+	if os.Args[1] == "version" {
+		fmt.Printf("Grus %s\n", version)
+		os.Exit(0)
+	}
+
+	dicts := []string{
+		"/usr/local/share/dict/words",
+		"/usr/share/dict/words",
+		"/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...)
+	}
+
+	// Check if user has asked to search in all dictionaries.
+	searchAll := false
+	searchAllEnv := os.Getenv("GRUS_SEARCH_ALL")
+	if searchAllEnv == "true" ||
+		searchAllEnv == "1" {
+		searchAll = true
+	}
+
+	// Check if user wants anagrams.
+	anagrams := false
+	anagramsEnv := os.Getenv("GRUS_ANAGRAMS")
+	if anagramsEnv == "true" ||
+		anagramsEnv == "1" {
+		anagrams = true
+	}
+
+	for _, 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
+		}
+
+		file, err := os.Open(dict)
+		panicOnErr(err)
+		defer file.Close()
+
+		// We use this to record if the word was unjumbled.
+		unjumbled := false
+
+		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 !anagrams {
+					os.Exit(0)
+				}
+				unjumbled = true
+			}
+		}
+		panicOnErr(scanner.Err())
+
+		// If word was unjumbled & user hasn't asked to search
+		// in all dictionaries then exit the program otherwise
+		// keep searching in other dictionaries.
+		if unjumbled &&
+			!searchAll {
+			os.Exit(0)
+		}
+	}
+}
+
+func panicOnErr(err error) {
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/main_openbsd.go b/main_openbsd.go
new file mode 100644
index 0000000..7d466ee
--- /dev/null
+++ b/main_openbsd.go
@@ -0,0 +1,44 @@
+// +build openbsd
+
+package main
+
+import (
+	"os"
+
+	"golang.org/x/sys/unix"
+	"tildegit.org/andinus/lynx"
+)
+
+func main() {
+	err := unix.PledgePromises("unveil stdio rpath")
+	panicOnErr(err)
+
+	unveil()
+
+	// Drop unveil from promises.
+	err = unix.PledgePromises("stdio rpath")
+	panicOnErr(err)
+
+	grus()
+}
+
+func unveil() {
+	paths := make(map[string]string)
+
+	paths["/usr/share/dict"] = "r"
+	paths["/usr/local/share/dict"] = "r"
+
+	// Unveil user defined dictionaries.
+	if len(os.Args) >= 3 {
+		for _, dict := range os.Args[2:] {
+			paths[dict] = "r"
+		}
+	}
+	// This will not return error if the file doesn't exist.
+	err := lynx.UnveilPaths(paths)
+	panicOnErr(err)
+
+	// Block further unveil calls.
+	err = lynx.UnveilBlock()
+	panicOnErr(err)
+}
diff --git a/main_other.go b/main_other.go
new file mode 100644
index 0000000..88824ad
--- /dev/null
+++ b/main_other.go
@@ -0,0 +1,7 @@
+// +build !openbsd
+
+package main
+
+func main() {
+	grus()
+}
hoang/Nim/commit/compiler/passes.nim?h=devel&id=c40aac8e2036924ec88bec9c44a33a044f346baa'>c40aac8e2 ^
5b28d0820 ^



1a61c4d46 ^
e25474154 ^
c40aac8e2 ^

be6474af6 ^

ca637c019 ^
e25474154 ^
c40aac8e2 ^

e25474154 ^

c40aac8e2 ^
e25474154 ^

c40aac8e2 ^
e25474154 ^
091c1b307 ^



e25474154 ^
c40aac8e2 ^
e25474154 ^


9e6fb3f69 ^
773d17cd1 ^
9e6fb3f69 ^
091c1b307 ^
46efaf294 ^
091c1b307 ^

9e6fb3f69 ^

091c1b307 ^


9e6fb3f69 ^
091c1b307 ^
9e6fb3f69 ^

c40aac8e2 ^

9e6fb3f69 ^
e25474154 ^
c40aac8e2 ^
9e6fb3f69 ^

c40aac8e2 ^

9e6fb3f69 ^
c40aac8e2 ^
720c73e6d ^
7ebaf4489 ^
e25474154 ^
c40aac8e2 ^
46efaf294 ^
7bf98411b ^
c40aac8e2 ^
46efaf294 ^
e25474154 ^
c40aac8e2 ^

e25474154 ^
7bf98411b ^
c40aac8e2 ^

7e31134ff ^


c40aac8e2 ^

e25474154 ^
7bf98411b ^
c40aac8e2 ^
e25474154 ^
c40aac8e2 ^
46efaf294 ^
7ebaf4489 ^
c40aac8e2 ^

46efaf294 ^
e25474154 ^
c40aac8e2 ^
bc9015df5 ^






31a994cc1 ^
bc9015df5 ^


31a994cc1 ^
bc9015df5 ^






c40aac8e2 ^
9e6fb3f69 ^
773d17cd1 ^
9f142e199 ^
c40aac8e2 ^
e25474154 ^
e25474154 ^

36e25a684 ^
c40aac8e2 ^
9e6fb3f69 ^
c40aac8e2 ^
8710a3738 ^
def61c9fc ^
c40aac8e2 ^
e25474154 ^
e92a7fd50 ^
26b853923 ^
e25474154 ^
c40aac8e2 ^
773d17cd1 ^
c617479c6 ^

c40aac8e2 ^
31a994cc1 ^


bc9015df5 ^

c617479c6 ^
c40aac8e2 ^
9f142e199 ^
27dc54cbd ^
c40aac8e2 ^
50f62ff44 ^
0a624bec1 ^






50f62ff44 ^
e2af48643 ^
0a624bec1 ^


e25474154 ^
c40aac8e2 ^
46efaf294 ^
7bf98411b ^
92b8fac94 ^
31a994cc1 ^
9e6fb3f69 ^
7ebaf4489 ^
9f142e199 ^


46efaf294 ^
e92a7fd50 ^
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231