/***************************************************************************** * Eliot * Copyright (C) 1999-2007 Antoine Fraboulet & Olivier Teulière * Authors: Antoine Fraboulet * Olivier Teulière * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *****************************************************************************/ #include "config.h" #include #include #include #include #include #include #include #include #if ENABLE_NLS # include # define _(String) gettext(String) #else # define _(String) String #endif #ifdef WIN32 # include #endif #include "compdic.h" #include "dic_exception.h" #include "encoding.h" #include "header.h" using namespace std; // Useful shortcut #define fmt(a) boost::format(a) void readLetters(const string &iFileName, CompDic &ioBuilder) { ifstream in(iFileName.c_str()); if (!in.is_open()) throw DicException((fmt(_("Could not open file '%1%'")) % iFileName).str()); // Use a more friendly type name typedef boost::tokenizer, std::wstring::const_iterator, std::wstring> Tokenizer; int lineNb = 1; string line; while (getline(in, line)) { // Ignore empty lines if (line == "" || line == "\r" || line == "\n") continue; // If there is a BOM in the file, remove it from the first line if (ioBuilder.getLettersCount() == 0 && line.size() >= 3 && (uint8_t)line[0] == 0xEF && (uint8_t)line[1] == 0xBB && (uint8_t)line[2] == 0xBF) { line = line.substr(3); } // Convert the line to a wstring const wstring &wline = readFromUTF8(line, "readLetters (1)"); // Split the lines on space characters boost::char_separator sep(L" "); Tokenizer tok(wline, sep); Tokenizer::iterator it; vector tokens(tok.begin(), tok.end()); // We expect at least 5 fields on the line if (tokens.size() < 5) { ostringstream ss; ss << fmt(_("readLetters: Not enough fields " "in %1% (line %2%)")) % iFileName % lineNb; throw DicException(ss.str()); } // The first field is a single character wstring letter = tokens[0]; if (letter.size() != 1) { ostringstream ss; ss << fmt(_("readLetters: Invalid letter at line %1% " "(only one character allowed)")) % lineNb; throw DicException(ss.str()); } vector inputs; if (tokens.size() > 5) { inputs = vector(tokens.begin() + 5, tokens.end()); } ioBuilder.addLetter(letter[0], wtoi(tokens[1].c_str()), wtoi(tokens[2].c_str()), wtoi(tokens[3].c_str()), wtoi(tokens[4].c_str()), inputs); ++lineNb; } } void printUsage(const string &iBinaryName) { cout << "Usage: " << iBinaryName << " [options]" << endl << _("Mandatory options:") << endl << _(" -d, --dicname Set the dictionary name and version") << endl << _(" -l, --letters Path to the file containing the letters (see below)") << endl << _(" -i, --input Path to the uncompressed dictionary file (encoded in UTF-8)") << endl << _(" The words must be in alphabetical order, without duplicates") << endl << _(" -o, --output Path to the generated compressed dictionary file") << endl << _("Other options:") << endl << _(" -h, --help Print this help and exit") << endl << _("Example:") << endl << " " << iBinaryName << _(" -d 'ODS 5.0' -l letters.txt -i ods5.txt -o ods5.dawg") << endl << endl << _("The file containing the letters (--letters switch) must be UTF-8 encoded.") << endl << _("Each line corresponds to one letter, and must contain at least 5 fields separated with " "one or more space(s).") << endl << _(" - 1st field: the letter itself, as stored in the input file (single character)") << endl << _(" - 2nd field: the points of the letter") << endl << _(" - 3rd field: the frequency of the letter (how many letters of this kind in the game)") << endl << _(" - 4th field: 1 if the letter is considered as a vowel in Scrabble game, 0 otherwise") << endl << _(" - 5th field: 1 if the letter is considered as a consonant in Scrabble game, 0 otherwise") << endl << _(" - 6th field (optional): display string for the letter (default: the letter itself)") << endl << _(" - other fields (optional): input strings for the letter, in addition to the display string") << endl << endl << _("Example for french:") << endl << "A 1 9 1 0" << endl << "[...]" << endl << "Z 10 1 0 1" << endl << "? 0 2 1 1" << endl << endl << _("Example for catalan:") << endl << "A 1 12 1 0" << endl << "[...]" << endl // TRANSLATORS: the first "L.L" must be translated "L·L", // and the last one translated "ĿL" << _("W 10 1 0 1 L.L L.L L-L L.L") << endl << "X 10 1 0 1" << endl << "Y 10 1 0 1 NY" << endl << "[...]" << endl; } int main(int argc, char* argv[]) { #if HAVE_SETLOCALE // Set locale via LC_ALL setlocale(LC_ALL, ""); #endif #if ENABLE_NLS // Set the message domain #ifdef WIN32 // Get the absolute path, as returned by GetFullPathName() char baseDir[MAX_PATH]; GetFullPathName(argv[0], MAX_PATH, baseDir, NULL); char *pos = strrchr(baseDir, L'\\'); if (pos) *pos = '\0'; const string localeDir = baseDir + string("\\locale"); #else static const string localeDir = LOCALEDIR; #endif bindtextdomain(PACKAGE, localeDir.c_str()); textdomain(PACKAGE); #endif static const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"dicname", required_argument, NULL, 'd'}, {"letters", required_argument, NULL, 'l'}, {"input", required_argument, NULL, 'i'}, {"output", required_argument, NULL, 'o'}, {0, 0, 0, 0} }; static const char short_options[] = "hd:l:i:o:"; bool found_d = false; bool found_l = false; bool found_i = false; bool found_o = false; string dicName; string inFileName; string outFileName; CompDic builder; int res; int option_index = 1; try { while ((res = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) { switch (res) { case 'h': printUsage(argv[0]); exit(0); case 'd': found_d = true; dicName = optarg; break; case 'l': found_l = true; readLetters(optarg, builder); break; case 'i': found_i = true; inFileName = optarg; break; case 'o': found_o = true; outFileName = optarg; break; } } // Check mandatory options if (!found_d || !found_l || !found_i || !found_o) { cerr << _("A mandatory option is missing") << endl; printUsage(argv[0]); exit(1); } // Generate the dictionary const Header &header = builder.generateDawg(inFileName, outFileName, dicName); // Print the header header.print(cout); cout << fmt(_(" Load time: %1% s")) % builder.getLoadTime() << endl; cout << fmt(_(" Compression time: %1% s")) % builder.getBuildTime() << endl; #ifdef CHECK_RECURSION cout << fmt(_(" Maximum recursion level reached: %1%")) % builder.getMaxRecursion() << endl; #endif return 0; } catch (const BaseException &e) { cerr << "Exception caught: " << e.what() << "\n" << e.getStackTrace(); } catch (std::exception &e) { cerr << "Exception caught: " << e.what() << endl; } return 1; }