diff options
author | simonb <simonb> | 2006-06-25 09:05:58 (GMT) |
---|---|---|
committer | simonb <simonb> | 2006-06-25 09:05:58 (GMT) |
commit | 80389b5dd5e7be4025cafbb2e7b055fd06f4f56d (patch) | |
tree | 1406d6c5044958bc40f2b7f4f8326ca8cc01629f /src | |
parent | 577859034db0e0e36ceab85ebba62e1018dd3361 (diff) | |
download | fluxbox-80389b5dd5e7be4025cafbb2e7b055fd06f4f56d.zip fluxbox-80389b5dd5e7be4025cafbb2e7b055fd06f4f56d.tar.bz2 |
support encodings in menu files
Diffstat (limited to 'src')
-rw-r--r-- | src/FbTk/FbString.cc | 49 | ||||
-rw-r--r-- | src/FbTk/FbString.hh | 20 | ||||
-rw-r--r-- | src/MenuCreator.cc | 132 | ||||
-rw-r--r-- | src/MenuCreator.hh | 23 |
4 files changed, 198 insertions, 26 deletions
diff --git a/src/FbTk/FbString.cc b/src/FbTk/FbString.cc index 93f6aa7..3ed1c70 100644 --- a/src/FbTk/FbString.cc +++ b/src/FbTk/FbString.cc | |||
@@ -54,6 +54,8 @@ static iconv_t *iconv_convs = 0; | |||
54 | static int iconv_convs[CONVSIZE]; | 54 | static int iconv_convs[CONVSIZE]; |
55 | #endif // HAVE_ICONV | 55 | #endif // HAVE_ICONV |
56 | 56 | ||
57 | static std::string locale_codeset; | ||
58 | |||
57 | /// Initialise all of the iconv conversion descriptors | 59 | /// Initialise all of the iconv conversion descriptors |
58 | void init() { | 60 | void init() { |
59 | setlocale(LC_CTYPE, ""); | 61 | setlocale(LC_CTYPE, ""); |
@@ -65,9 +67,9 @@ void init() { | |||
65 | iconv_convs = new iconv_t[CONVSIZE]; | 67 | iconv_convs = new iconv_t[CONVSIZE]; |
66 | 68 | ||
67 | #ifdef CODESET | 69 | #ifdef CODESET |
68 | std::string locale_codeset = nl_langinfo(CODESET); | 70 | locale_codeset = nl_langinfo(CODESET); |
69 | #else // openbsd doesnt have this (yet?) | 71 | #else // openbsd doesnt have this (yet?) |
70 | std::string locale_codeset = ""; | 72 | locale_codeset = ""; |
71 | std::string locale = setlocale(LC_CTYPE, NULL); | 73 | std::string locale = setlocale(LC_CTYPE, NULL); |
72 | size_t pos = locale.find('.'); | 74 | size_t pos = locale.find('.'); |
73 | if (pos != std::string::npos) | 75 | if (pos != std::string::npos) |
@@ -229,4 +231,47 @@ bool haveUTF8() { | |||
229 | 231 | ||
230 | }; // end namespace StringUtil | 232 | }; // end namespace StringUtil |
231 | 233 | ||
234 | StringConvertor::StringConvertor(EncodingTarget target): m_iconv((iconv_t)(-1)) { | ||
235 | #ifdef HAVE_ICONV | ||
236 | if (target == ToLocaleStr) | ||
237 | m_destencoding = FbStringUtil::locale_codeset; | ||
238 | else | ||
239 | m_destencoding = "UTF-8"; | ||
240 | #endif | ||
241 | } | ||
242 | |||
243 | StringConvertor::~StringConvertor() { | ||
244 | #ifdef HAVE_ICONV | ||
245 | if (m_iconv != ((iconv_t)-1)) | ||
246 | iconv_close(m_iconv); | ||
247 | #endif | ||
248 | } | ||
249 | |||
250 | bool StringConvertor::setSource(const std::string &encoding) { | ||
251 | #ifdef HAVE_ICONV | ||
252 | std::string tempenc = encoding; | ||
253 | if (encoding == "") | ||
254 | tempenc = FbStringUtil::locale_codeset; | ||
255 | |||
256 | iconv_t newiconv = iconv_open(m_destencoding.c_str(), tempenc.c_str()); | ||
257 | if (newiconv == ((iconv_t)(-1))) | ||
258 | return false; | ||
259 | else { | ||
260 | iconv_close(m_iconv); | ||
261 | m_iconv = newiconv; | ||
262 | return true; | ||
263 | } | ||
264 | #else | ||
265 | return false; | ||
266 | #endif | ||
267 | } | ||
268 | |||
269 | std::string StringConvertor::recode(const std::string &src) { | ||
270 | #ifdef HAVE_ICONV | ||
271 | return FbStringUtil::recode(m_iconv, src); | ||
272 | #else | ||
273 | return src; | ||
274 | #endif | ||
275 | } | ||
276 | |||
232 | }; // end namespace FbTk | 277 | }; // end namespace FbTk |
diff --git a/src/FbTk/FbString.hh b/src/FbTk/FbString.hh index 011d47a..cfa44d9 100644 --- a/src/FbTk/FbString.hh +++ b/src/FbTk/FbString.hh | |||
@@ -52,6 +52,26 @@ std::string FbStrToLocale(const FbString &src); | |||
52 | bool haveUTF8(); | 52 | bool haveUTF8(); |
53 | 53 | ||
54 | } // namespace FbStringUtil | 54 | } // namespace FbStringUtil |
55 | |||
56 | class StringConvertor { | ||
57 | public: | ||
58 | |||
59 | enum EncodingTarget { ToFbString, ToLocaleStr }; | ||
60 | |||
61 | StringConvertor(EncodingTarget target); | ||
62 | ~StringConvertor(); | ||
63 | |||
64 | bool setSource(const std::string &encoding); | ||
65 | void reset() { m_iconv = ((iconv_t)(-1)); } | ||
66 | |||
67 | std::string recode(const std::string &src); | ||
68 | |||
69 | private: | ||
70 | iconv_t m_iconv; | ||
71 | |||
72 | std::string m_destencoding; | ||
73 | }; | ||
74 | |||
55 | } // namespace FbTk | 75 | } // namespace FbTk |
56 | 76 | ||
57 | #endif // FBTK_FBSTRING_HH | 77 | #endif // FBTK_FBSTRING_HH |
diff --git a/src/MenuCreator.cc b/src/MenuCreator.cc index 2aa73ba..e33db19 100644 --- a/src/MenuCreator.cc +++ b/src/MenuCreator.cc | |||
@@ -55,6 +55,11 @@ | |||
55 | #include <iostream> | 55 | #include <iostream> |
56 | using namespace std; | 56 | using namespace std; |
57 | 57 | ||
58 | std::list<std::string> MenuCreator::encoding_stack; | ||
59 | std::list<size_t> MenuCreator::stacksize_stack; | ||
60 | |||
61 | FbTk::StringConvertor MenuCreator::m_stringconvertor(FbTk::StringConvertor::ToFbString); | ||
62 | |||
58 | static void createStyleMenu(FbTk::Menu &parent, const std::string &label, | 63 | static void createStyleMenu(FbTk::Menu &parent, const std::string &label, |
59 | const std::string &directory) { | 64 | const std::string &directory) { |
60 | // perform shell style ~ home directory expansion | 65 | // perform shell style ~ home directory expansion |
@@ -131,8 +136,9 @@ class ParseItem { | |||
131 | public: | 136 | public: |
132 | explicit ParseItem(FbTk::Menu *menu):m_menu(menu) {} | 137 | explicit ParseItem(FbTk::Menu *menu):m_menu(menu) {} |
133 | 138 | ||
134 | inline void load(Parser &p) { | 139 | inline void load(Parser &p, FbTk::StringConvertor &m_labelconvertor) { |
135 | p>>m_key>>m_label>>m_cmd>>m_icon; | 140 | p>>m_key>>m_label>>m_cmd>>m_icon; |
141 | m_label.second = m_labelconvertor.recode(m_label.second); | ||
136 | } | 142 | } |
137 | inline const std::string &icon() const { return m_icon.second; } | 143 | inline const std::string &icon() const { return m_icon.second; } |
138 | inline const std::string &command() const { return m_cmd.second; } | 144 | inline const std::string &command() const { return m_cmd.second; } |
@@ -158,20 +164,20 @@ public: | |||
158 | } | 164 | } |
159 | }; | 165 | }; |
160 | 166 | ||
161 | static void translateMenuItem(Parser &parse, ParseItem &item); | 167 | static void translateMenuItem(Parser &parse, ParseItem &item, FbTk::StringConvertor &labelconvertor); |
162 | 168 | ||
163 | 169 | ||
164 | static void parseMenu(Parser &pars, FbTk::Menu &menu) { | 170 | static void parseMenu(Parser &pars, FbTk::Menu &menu, FbTk::StringConvertor &label_convertor) { |
165 | ParseItem pitem(&menu); | 171 | ParseItem pitem(&menu); |
166 | while (!pars.eof()) { | 172 | while (!pars.eof()) { |
167 | pitem.load(pars); | 173 | pitem.load(pars, label_convertor); |
168 | if (pitem.key() == "end") | 174 | if (pitem.key() == "end") |
169 | return; | 175 | return; |
170 | translateMenuItem(pars, pitem); | 176 | translateMenuItem(pars, pitem, label_convertor); |
171 | } | 177 | } |
172 | } | 178 | } |
173 | 179 | ||
174 | static void translateMenuItem(Parser &parse, ParseItem &pitem) { | 180 | static void translateMenuItem(Parser &parse, ParseItem &pitem, FbTk::StringConvertor &labelconvertor) { |
175 | if (pitem.menu() == 0) | 181 | if (pitem.menu() == 0) |
176 | throw string("translateMenuItem: We must have a menu in ParseItem!"); | 182 | throw string("translateMenuItem: We must have a menu in ParseItem!"); |
177 | 183 | ||
@@ -256,14 +262,12 @@ static void translateMenuItem(Parser &parse, ParseItem &pitem) { | |||
256 | (filelist[file_index][0] != '.') && | 262 | (filelist[file_index][0] != '.') && |
257 | (thisfile[thisfile.length() - 1] != '~')) { | 263 | (thisfile[thisfile.length() - 1] != '~')) { |
258 | MenuCreator::createFromFile(thisfile, menu, false); | 264 | MenuCreator::createFromFile(thisfile, menu, false); |
259 | Fluxbox::instance()->saveMenuFilename(thisfile.c_str()); | ||
260 | } | 265 | } |
261 | } | 266 | } |
262 | 267 | ||
263 | } else { | 268 | } else { |
264 | // inject this file into the current menu | 269 | // inject this file into the current menu |
265 | MenuCreator::createFromFile(newfile, menu, false); | 270 | MenuCreator::createFromFile(newfile, menu, false); |
266 | Fluxbox::instance()->saveMenuFilename(newfile.c_str()); | ||
267 | } | 271 | } |
268 | 272 | ||
269 | safe_counter--; | 273 | safe_counter--; |
@@ -280,7 +284,7 @@ static void translateMenuItem(Parser &parse, ParseItem &pitem) { | |||
280 | else | 284 | else |
281 | submenu->setLabel(str_label); | 285 | submenu->setLabel(str_label); |
282 | 286 | ||
283 | parseMenu(parse, *submenu); | 287 | parseMenu(parse, *submenu, labelconvertor); |
284 | submenu->updateMenu(); | 288 | submenu->updateMenu(); |
285 | menu.insert(str_label, submenu); | 289 | menu.insert(str_label, submenu); |
286 | // save to screen list so we can delete it later | 290 | // save to screen list so we can delete it later |
@@ -310,6 +314,10 @@ static void translateMenuItem(Parser &parse, ParseItem &pitem) { | |||
310 | } | 314 | } |
311 | } else if (str_key == "separator") { | 315 | } else if (str_key == "separator") { |
312 | menu.insert(new FbTk::MenuSeparator()); | 316 | menu.insert(new FbTk::MenuSeparator()); |
317 | } else if (str_key == "encoding") { | ||
318 | MenuCreator::startEncoding(str_cmd); | ||
319 | } else if (str_key == "endencoding") { | ||
320 | MenuCreator::endEncoding(); | ||
313 | } | 321 | } |
314 | else { // ok, if we didn't find any special menu item we try with command parser | 322 | else { // ok, if we didn't find any special menu item we try with command parser |
315 | // we need to attach command with arguments so command parser can parse it | 323 | // we need to attach command with arguments so command parser can parse it |
@@ -337,11 +345,11 @@ static void translateMenuItem(Parser &parse, ParseItem &pitem) { | |||
337 | } | 345 | } |
338 | 346 | ||
339 | 347 | ||
340 | static void parseWindowMenu(Parser &parse, FbTk::Menu &menu) { | 348 | static void parseWindowMenu(Parser &parse, FbTk::Menu &menu, FbTk::StringConvertor &labelconvertor) { |
341 | 349 | ||
342 | ParseItem pitem(&menu); | 350 | ParseItem pitem(&menu); |
343 | while (!parse.eof()) { | 351 | while (!parse.eof()) { |
344 | pitem.load(parse); | 352 | pitem.load(parse, labelconvertor); |
345 | if (MenuCreator::createWindowMenuItem(pitem.key(), pitem.label(), menu)) | 353 | if (MenuCreator::createWindowMenuItem(pitem.key(), pitem.label(), menu)) |
346 | continue; | 354 | continue; |
347 | 355 | ||
@@ -349,12 +357,12 @@ static void parseWindowMenu(Parser &parse, FbTk::Menu &menu) { | |||
349 | return; | 357 | return; |
350 | } else if (pitem.key() == "submenu") { | 358 | } else if (pitem.key() == "submenu") { |
351 | FbTk::Menu *submenu = MenuCreator::createMenu(pitem.label(), menu.screenNumber()); | 359 | FbTk::Menu *submenu = MenuCreator::createMenu(pitem.label(), menu.screenNumber()); |
352 | parseWindowMenu(parse, *submenu); | 360 | parseWindowMenu(parse, *submenu, labelconvertor); |
353 | submenu->updateMenu(); | 361 | submenu->updateMenu(); |
354 | menu.insert(pitem.label(), submenu); | 362 | menu.insert(pitem.label(), submenu); |
355 | 363 | ||
356 | } else { // try non window menu specific stuff | 364 | } else { // try non window menu specific stuff |
357 | translateMenuItem(parse, pitem); | 365 | translateMenuItem(parse, pitem, labelconvertor); |
358 | } | 366 | } |
359 | } | 367 | } |
360 | } | 368 | } |
@@ -373,11 +381,11 @@ FbTk::Menu *MenuCreator::createMenu(const std::string &label, int screen_number) | |||
373 | return menu; | 381 | return menu; |
374 | } | 382 | } |
375 | 383 | ||
376 | bool getStart(FbMenuParser &parser, std::string &label) { | 384 | bool getStart(FbMenuParser &parser, std::string &label, FbTk::StringConvertor &labelconvertor) { |
377 | ParseItem pitem(0); | 385 | ParseItem pitem(0); |
378 | while (!parser.eof()) { | 386 | while (!parser.eof()) { |
379 | // get first begin line | 387 | // get first begin line |
380 | pitem.load(parser); | 388 | pitem.load(parser, labelconvertor); |
381 | if (pitem.key() == "begin") { | 389 | if (pitem.key() == "begin") { |
382 | break; | 390 | break; |
383 | } | 391 | } |
@@ -391,19 +399,22 @@ bool getStart(FbMenuParser &parser, std::string &label) { | |||
391 | 399 | ||
392 | FbTk::Menu *MenuCreator::createFromFile(const std::string &filename, int screen_number, bool require_begin) { | 400 | FbTk::Menu *MenuCreator::createFromFile(const std::string &filename, int screen_number, bool require_begin) { |
393 | std::string real_filename = FbTk::StringUtil::expandFilename(filename); | 401 | std::string real_filename = FbTk::StringUtil::expandFilename(filename); |
402 | Fluxbox::instance()->saveMenuFilename(real_filename.c_str()); | ||
403 | |||
394 | FbMenuParser parser(real_filename); | 404 | FbMenuParser parser(real_filename); |
395 | if (!parser.isLoaded()) | 405 | if (!parser.isLoaded()) |
396 | return 0; | 406 | return 0; |
397 | 407 | ||
398 | Fluxbox::instance()->saveMenuFilename(real_filename.c_str()); | ||
399 | |||
400 | std::string label; | 408 | std::string label; |
401 | if (require_begin && !getStart(parser, label)) | 409 | if (require_begin && !getStart(parser, label, m_stringconvertor)) |
402 | return 0; | 410 | return 0; |
403 | 411 | ||
404 | FbTk::Menu *menu = createMenu(label, screen_number); | 412 | FbTk::Menu *menu = createMenu(label, screen_number); |
405 | if (menu != 0) | 413 | if (menu != 0) { |
406 | parseMenu(parser, *menu); | 414 | startFile(); |
415 | parseMenu(parser, *menu, m_stringconvertor); | ||
416 | endFile(); | ||
417 | } | ||
407 | 418 | ||
408 | return menu; | 419 | return menu; |
409 | } | 420 | } |
@@ -418,10 +429,13 @@ bool MenuCreator::createFromFile(const std::string &filename, | |||
418 | return false; | 429 | return false; |
419 | 430 | ||
420 | std::string label; | 431 | std::string label; |
421 | if (require_begin && !getStart(parser, label)) | 432 | if (require_begin && !getStart(parser, label, m_stringconvertor)) |
422 | return false; | 433 | return false; |
423 | 434 | ||
424 | parseMenu(parser, inject_into); | 435 | startFile(); |
436 | parseMenu(parser, inject_into, m_stringconvertor); | ||
437 | endFile(); | ||
438 | |||
425 | return true; | 439 | return true; |
426 | } | 440 | } |
427 | 441 | ||
@@ -436,10 +450,13 @@ bool MenuCreator::createWindowMenuFromFile(const std::string &filename, | |||
436 | 450 | ||
437 | std::string label; | 451 | std::string label; |
438 | 452 | ||
439 | if (require_begin && !getStart(parser, label)) | 453 | if (require_begin && !getStart(parser, label, m_stringconvertor)) |
440 | return false; | 454 | return false; |
441 | 455 | ||
442 | parseWindowMenu(parser, inject_into); | 456 | startFile(); |
457 | parseWindowMenu(parser, inject_into, m_stringconvertor); | ||
458 | endFile(); | ||
459 | |||
443 | return true; | 460 | return true; |
444 | } | 461 | } |
445 | 462 | ||
@@ -580,3 +597,70 @@ bool MenuCreator::createWindowMenuItem(const std::string &type, | |||
580 | 597 | ||
581 | return true; | 598 | return true; |
582 | } | 599 | } |
600 | |||
601 | /* push our encoding-stacksize onto the stack */ | ||
602 | void MenuCreator::startFile() { | ||
603 | if (encoding_stack.empty()) | ||
604 | m_stringconvertor.setSource(""); | ||
605 | stacksize_stack.push_back(encoding_stack.size()); | ||
606 | } | ||
607 | |||
608 | /** | ||
609 | * Pop necessary encodings from the stack | ||
610 | * (and endEncoding the final one) to our matching encoding-stacksize. | ||
611 | */ | ||
612 | void MenuCreator::endFile() { | ||
613 | size_t target_size = stacksize_stack.back(); | ||
614 | size_t curr_size = encoding_stack.size(); | ||
615 | |||
616 | if (target_size != curr_size) { | ||
617 | _FB_USES_NLS; | ||
618 | cerr<<_FB_CONSOLETEXT(Menu, ErrorEndEncoding, "Warning: unbalanced [encoding] tags", "User menu file had unbalanced [encoding] tags")<<endl; | ||
619 | } | ||
620 | |||
621 | for (; curr_size > (target_size+1); --curr_size) | ||
622 | encoding_stack.pop_back(); | ||
623 | |||
624 | if (curr_size == (target_size+1)) | ||
625 | endEncoding(); | ||
626 | |||
627 | stacksize_stack.pop_back(); | ||
628 | } | ||
629 | |||
630 | /** | ||
631 | * Push the encoding onto the stack, and make it active. | ||
632 | */ | ||
633 | void MenuCreator::startEncoding(const std::string &encoding) { | ||
634 | // we push it regardless of whether it's valid, since we | ||
635 | // need to stay balanced with the endEncodings. | ||
636 | encoding_stack.push_back(encoding); | ||
637 | |||
638 | // this won't change if it doesn't succeed | ||
639 | m_stringconvertor.setSource(encoding); | ||
640 | } | ||
641 | |||
642 | /** | ||
643 | * Pop the encoding from the stack, unless we are at our stacksize limit. | ||
644 | * Restore the previous (valid) encoding. | ||
645 | */ | ||
646 | void MenuCreator::endEncoding() { | ||
647 | size_t min_size = stacksize_stack.back(); | ||
648 | if (encoding_stack.size() <= min_size) { | ||
649 | // TODO: nls | ||
650 | _FB_USES_NLS; | ||
651 | cerr<<_FB_CONSOLETEXT(Menu, ErrorEndEncoding, "Warning: unbalanced [encoding] tags", "User menu file had unbalanced [encoding] tags")<<endl; | ||
652 | return; | ||
653 | } | ||
654 | |||
655 | encoding_stack.pop_back(); | ||
656 | m_stringconvertor.reset(); | ||
657 | |||
658 | std::list<std::string>::reverse_iterator it = encoding_stack.rbegin(); | ||
659 | std::list<std::string>::reverse_iterator it_end = encoding_stack.rend(); | ||
660 | while (it != it_end && !m_stringconvertor.setSource(*it)) | ||
661 | ++it; | ||
662 | |||
663 | if (it == it_end) | ||
664 | m_stringconvertor.setSource(""); | ||
665 | } | ||
666 | |||
diff --git a/src/MenuCreator.hh b/src/MenuCreator.hh index 66e7408..927b564 100644 --- a/src/MenuCreator.hh +++ b/src/MenuCreator.hh | |||
@@ -23,7 +23,10 @@ | |||
23 | #ifndef MENUCREATOR_HH | 23 | #ifndef MENUCREATOR_HH |
24 | #define MENUCREATOR_HH | 24 | #define MENUCREATOR_HH |
25 | 25 | ||
26 | #include "FbTk/FbString.hh" | ||
27 | |||
26 | #include <string> | 28 | #include <string> |
29 | #include <list> | ||
27 | 30 | ||
28 | namespace FbTk { | 31 | namespace FbTk { |
29 | class Menu; | 32 | class Menu; |
@@ -44,6 +47,26 @@ public: | |||
44 | static bool createWindowMenuItem(const std::string &type, const std::string &label, | 47 | static bool createWindowMenuItem(const std::string &type, const std::string &label, |
45 | FbTk::Menu &inject_into); | 48 | FbTk::Menu &inject_into); |
46 | 49 | ||
50 | /** | ||
51 | * Encoding-related helpers (encoding, aka codeset) | ||
52 | */ | ||
53 | |||
54 | // Files are guaranteed to be "balanced", unlike user-created [encoding] tags. | ||
55 | static void startFile(); | ||
56 | static void endFile(); | ||
57 | |||
58 | static void startEncoding(const std::string &encoding); | ||
59 | static void endEncoding(); | ||
60 | |||
61 | private: | ||
62 | // stack of encodings | ||
63 | static std::list<std::string> encoding_stack; | ||
64 | // stack of ints, representing stack size as each file is entered | ||
65 | // (a file should never end more encodings than it starts) | ||
66 | static std::list<size_t> stacksize_stack; | ||
67 | |||
68 | static FbTk::StringConvertor m_stringconvertor; | ||
69 | |||
47 | }; | 70 | }; |
48 | 71 | ||
49 | #endif // MENUCREATOR_HH | 72 | #endif // MENUCREATOR_HH |