1<?php
2use Gettext\Languages\Exporter\Exporter;
3use Gettext\Languages\Language;
4
5// Let's start by imposing that we don't accept any error or warning.
6// This is a really life-saving approach.
7error_reporting(E_ALL);
8set_error_handler(function ($errno, $errstr, $errfile, $errline) {
9    Enviro::echoErr("$errstr\nFile: $errfile\nLine: $errline\nCode: $errno\n");
10    die(5);
11});
12
13require_once dirname(__DIR__).'/src/autoloader.php';
14
15// Parse the command line options
16Enviro::initialize();
17
18try {
19    if (isset(Enviro::$languages)) {
20        $languages = array();
21        foreach (Enviro::$languages as $languageId) {
22            $language = Language::getById($languageId);
23            if (!isset($language)) {
24                throw new Exception("Unable to find the language with id '$languageId'");
25            }
26            $languages[] = $language;
27        }
28    } else {
29        $languages = Language::getAll();
30    }
31    if (Enviro::$reduce) {
32        $languages = Enviro::reduce($languages);
33    }
34    if (isset(Enviro::$outputFilename)) {
35        echo call_user_func(array(Exporter::getExporterClassName(Enviro::$outputFormat), 'toFile'), $languages, Enviro::$outputFilename, array('us-ascii' => Enviro::$outputUSAscii));
36    } else {
37        echo call_user_func(array(Exporter::getExporterClassName(Enviro::$outputFormat), 'toString'), $languages, array('us-ascii' => Enviro::$outputUSAscii));
38    }
39} catch (Exception $x) {
40    Enviro::echoErr($x->getMessage()."\n");
41    Enviro::echoErr("Trace:\n");
42    Enviro::echoErr($x->getTraceAsString()."\n");
43    die(4);
44}
45
46die(0);
47
48/**
49 * Helper class to handle command line options.
50 */
51class Enviro
52{
53    /**
54     * Shall the output contain only US-ASCII characters?
55     * @var bool
56     */
57    public static $outputUSAscii;
58    /**
59     * The output format.
60     * @var string
61     */
62    public static $outputFormat;
63    /**
64     * Output file name.
65     * @var string
66     */
67    public static $outputFilename;
68    /**
69     * List of wanted language IDs; it not set: all languages will be returned.
70     * @var array|null
71     */
72    public static $languages;
73    /**
74     * Reduce the language list to the minimum common denominator.
75     * @var bool
76     */
77    public static $reduce;
78    /**
79     * Parse the command line options.
80     */
81    public static function initialize()
82    {
83        global $argv;
84        self::$outputUSAscii = false;
85        self::$outputFormat = null;
86        self::$outputFilename = null;
87        self::$languages = null;
88        self::$reduce = null;
89        $exporters = Exporter::getExporters();
90        if (isset($argv) && is_array($argv)) {
91            foreach ($argv as $argi => $arg) {
92                if ($argi === 0) {
93                    continue;
94                }
95                if (is_string($arg)) {
96                    $argLC = trim(strtolower($arg));
97                    switch ($argLC) {
98                        case '--us-ascii':
99                            self::$outputUSAscii = true;
100                            break;
101                        case '--reduce=yes':
102                            self::$reduce = true;
103                            break;
104                        case '--reduce=no':
105                            self::$reduce = false;
106                            break;
107                        default:
108                            if (preg_match('/^--output=.+$/', $argLC)) {
109                                if (isset(self::$outputFilename)) {
110                                    self::echoErr("The output file name has been specified more than once!\n");
111                                    self::showSyntax();
112                                    die(3);
113                                }
114                                list(, self::$outputFilename) = explode('=', $arg, 2);
115                                self::$outputFilename = trim(self::$outputFilename);
116                            } elseif (preg_match('/^--languages?=.+$/', $argLC)) {
117                                list(, $s) = explode('=', $arg, 2);
118                                $list = explode(',', $s);
119                                if (is_array(self::$languages)) {
120                                    self::$languages = array_merge(self::$languages, $list);
121                                } else {
122                                    self::$languages = $list;
123                                }
124                            } elseif (isset($exporters[$argLC])) {
125                                if (isset(self::$outputFormat)) {
126                                    self::echoErr("The output format has been specified more than once!\n");
127                                    self::showSyntax();
128                                    die(3);
129                                }
130                                self::$outputFormat = $argLC;
131                            } else {
132                                self::echoErr("Unknown option: $arg\n");
133                                self::showSyntax();
134                                die(2);
135                            }
136                            break;
137                    }
138                }
139            }
140        }
141        if (!isset(self::$outputFormat)) {
142            self::showSyntax();
143            die(1);
144        }
145        if (isset(self::$languages)) {
146            self::$languages = array_values(array_unique(self::$languages));
147        }
148        if (!isset(self::$reduce)) {
149            self::$reduce = isset(self::$languages) ? false : true;
150        }
151    }
152
153    /**
154     * Write out the syntax.
155     */
156    public static function showSyntax()
157    {
158        $exporters = array_keys(Exporter::getExporters(true));
159        self::echoErr("Syntax: php ".basename(__FILE__)." [--us-ascii] [--languages=<LanguageId>[,<LanguageId>,...]] [--reduce=yes|no] [--output=<file name>] <".implode('|', $exporters).">\n");
160        self::echoErr("Where:\n");
161        self::echoErr("--us-ascii : if specified, the output will contain only US-ASCII characters.\n");
162        self::echoErr("--languages: (or --language) export only the specified language codes.\n");
163        self::echoErr("             Separate languages with commas; you can also use this argument\n");
164        self::echoErr("             more than once; it's case insensitive and accepts both '_' and\n");
165        self::echoErr("             '-' as locale chunks separator (eg we accept 'it_IT' as well as\n");
166        self::echoErr("            'it-it').\n");
167        self::echoErr("--reduce   : if set to yes the output won't contain languages with the same\n");
168        self::echoErr("             base language and rules.\n For instance nl_BE ('Flemish') will be\n");
169        self::echoErr("             omitted because it's the same as nl ('Dutch').\n");
170        self::echoErr("             Defaults to 'no' --languages is specified, to 'yes' otherwise.\n");
171        self::echoErr("--output   : if specified, the output will be saved to <file name>. If not\n");
172        self::echoErr("             specified we'll output to standard output.\n");
173        self::echoErr("Output formats\n");
174        $len = max(array_map('strlen', $exporters));
175        foreach ($exporters as $exporter) {
176            self::echoErr(str_pad($exporter, $len).": ".Exporter::getExporterDescription($exporter)."\n");
177        }
178    }
179    /**
180     * Print a string to stderr.
181     * @param string $str The string to be printed out.
182     */
183    public static function echoErr($str)
184    {
185        $hStdErr = @fopen('php://stderr', 'a');
186        if ($hStdErr === false) {
187            echo $str;
188        } else {
189            fwrite($hStdErr, $str);
190            fclose($hStdErr);
191        }
192    }
193    /**
194     * Reduce a language list to the minimum common denominator.
195     * @param Language[] $languages
196     * @return Language[]
197     */
198    public static function reduce($languages)
199    {
200        for ($numChunks = 3; $numChunks >= 2; $numChunks--) {
201            $filtered = array();
202            foreach ($languages as $language) {
203                $chunks = explode('_', $language->id);
204                $compatibleFound = false;
205                if (count($chunks) === $numChunks) {
206                    $categoriesHash = serialize($language->categories);
207                    $otherIds = array();
208                    $otherIds[] = $chunks[0];
209                    for ($k = 2; $k < $numChunks; $k++) {
210                        $otherIds[] = $chunks[0].'_'.$chunks[$numChunks - 1];
211                    }
212
213                    foreach ($languages as $check) {
214                        foreach ($otherIds as $otherId) {
215                            if (($check->id === $otherId) && ($check->formula === $language->formula) && (serialize($check->categories) === $categoriesHash)) {
216                                $compatibleFound = true;
217                                break;
218                            }
219                        }
220                        if ($compatibleFound === true) {
221                            break;
222                        }
223                    }
224                }
225                if (!$compatibleFound) {
226                    $filtered[] = $language;
227                }
228            }
229            $languages = $filtered;
230        }
231
232        return $languages;
233    }
234}
235