1#include <dawgdic/completer.h>
2#include <dawgdic/dictionary.h>
3#include <dawgdic/ranked-completer.h>
4
5#include <fstream>
6#include <iostream>
7#include <string>
8#include <vector>
9
10namespace {
11
12class CommandOptions {
13 public:
14 CommandOptions()
15 : help_(false), guide_(false), ranked_(false),
16 dic_file_name_(), lexicon_file_name_() {}
17
18 // Reads options.
19 bool help() const {
20 return help_;
21 }
22 bool guide() const {
23 return guide_;
24 }
25 bool ranked() const {
26 return ranked_;
27 }
28 const std::string &dic_file_name() const {
29 return dic_file_name_;
30 }
31 const std::string &lexicon_file_name() const {
32 return lexicon_file_name_;
33 }
34
35 bool Parse(int argc, char *argv[]) {
36 for (int i = 1; i < argc; ++i) {
37 // Parses options.
38 if (argv[i][0] == '-' && argv[i][1] != '\0') {
39 for (int j = 1; argv[i][j] != '\0'; ++j) {
40 switch (argv[i][j]) {
41 case 'h': {
42 help_ = true;
43 break;
44 }
45 case 'g': {
46 guide_ = true;
47 break;
48 }
49 case 'r': {
50 ranked_ = true;
51 break;
52 }
53 default: {
54 // Invalid option.
55 return false;
56 }
57 }
58 }
59 } else if (dic_file_name_.empty()) {
60 dic_file_name_ = argv[i];
61 } else if (lexicon_file_name_.empty()) {
62 lexicon_file_name_ = argv[i];
63 } else {
64 // Too many arguments.
65 return false;
66 }
67 }
68
69 // Uses default settings for file names.
70 if (dic_file_name_.empty()) {
71 dic_file_name_ = "-";
72 }
73 if (lexicon_file_name_.empty()) {
74 lexicon_file_name_ = "-";
75 }
76 return true;
77 }
78
79 static void ShowUsage(std::ostream *output) {
80 *output << "Usage: - [Options] [DicFile] [LexiconFile]\n"
81 "\n"
82 "Options:\n"
83 " -h display this help and exit\n"
84 " -g load dictionary with guide\n"
85 " -r load dictionary with ranked guide\n";
86 *output << std::endl;
87 }
88
89private:
90 bool help_;
91 bool guide_;
92 bool ranked_;
93 std::string dic_file_name_;
94 std::string lexicon_file_name_;
95
96 // Disallows copies.
97 CommandOptions(const CommandOptions &);
98 CommandOptions &operator=(const CommandOptions &);
99};
100
101// Example of finding prefix keys from each line of an input text.
102void FindPrefixKeys(const dawgdic::Dictionary &dic, std::istream *input) {
103 std::string line;
104 while (std::getline(*input, line)) {
105 std::cout << line << ':';
106
107 dawgdic::BaseType index = dic.root();
108 for (std::size_t i = 0; i < line.length(); ++i) {
109 if (!dic.Follow(line[i], &index)) {
110 break;
111 }
112
113 // Reads a value.
114 if (dic.has_value(index)) {
115 std::cout << ' ';
116 std::cout.write(line.c_str(), i + 1);
117 std::cout << " = " << dic.value(index) << ';';
118 }
119 }
120 std::cout << std::endl;
121 }
122}
123
124// Example of completing ranked keys from each line of an input text.
125template <typename COMPLETER_TYPE, typename GUIDE_TYPE>
126void CompleteKeys(const dawgdic::Dictionary &dic,
127 const GUIDE_TYPE &guide, std::istream *input) {
128 COMPLETER_TYPE completer(dic, guide);
129 std::string line;
130 while (std::getline(*input, line)) {
131 std::cout << line << ':';
132
133 dawgdic::BaseType index = dic.root();
134 if (dic.Follow(line.c_str(), line.length(), &index)) {
135 completer.Start(index);
136 while (completer.Next()) {
137 std::cout << ' ' << line << completer.key()
138 << " = " << completer.value();
139 }
140 }
141 std::cout << std::endl;
142 }
143}
144
145} // namespace
146
147int main(int argc, char *argv[]) {
148 CommandOptions options;
149 if (!options.Parse(argc, argv)) {
150 CommandOptions::ShowUsage(&std::cerr);
151 return 1;
152 } else if (options.help()) {
153 CommandOptions::ShowUsage(&std::cerr);
154 return 0;
155 }
156
157 const std::string &dic_file_name = options.dic_file_name();
158 const std::string &lexicon_file_name = options.lexicon_file_name();
159
160 std::istream *dic_stream = &std::cin;
161 std::istream *lexicon_stream = &std::cin;
162
163 // Opens a dictionary file.
164 std::ifstream dic_file;
165 if (dic_file_name != "-") {
166 dic_file.open(dic_file_name.c_str(), std::ios::binary);
167 if (!dic_file) {
168 std::cerr << "error: failed to open DicFile: "
169 << dic_file_name << std::endl;
170 return 1;
171 }
172 dic_stream = &dic_file;
173 }
174
175 // Opens a lexicon file.
176 std::ifstream lexicon_file;
177 if (lexicon_file_name != "-") {
178 lexicon_file.open(lexicon_file_name.c_str(), std::ios::binary);
179 if (!lexicon_file) {
180 std::cerr << "error: failed to open LexiconFile: "
181 << lexicon_file_name << std::endl;
182 return 1;
183 }
184 lexicon_stream = &lexicon_file;
185 }
186
187 dawgdic::Dictionary dic;
188 if (!dic.Read(dic_stream)) {
189 std::cerr << "error: failed to read Dictionary" << std::endl;
190 return 1;
191 }
192
193 if (options.ranked()) {
194 dawgdic::RankedGuide guide;
195 if (!guide.Read(dic_stream)) {
196 std::cerr << "error: failed to read RankedGuide" << std::endl;
197 return 1;
198 }
199 CompleteKeys<dawgdic::RankedCompleter>(dic, guide, lexicon_stream);
200 } else if (options.guide()) {
201 dawgdic::Guide guide;
202 if (!guide.Read(dic_stream)) {
203 std::cerr << "error: failed to read Guide" << std::endl;
204 return 1;
205 }
206 CompleteKeys<dawgdic::Completer>(dic, guide, lexicon_stream);
207 } else {
208 FindPrefixKeys(dic, lexicon_stream);
209 }
210
211 return 0;
212}
213