OSDN Git Service

import the last version of the original mayu extracted by following command:
[yamy/yamy.git] / setting.cpp
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // setting.cpp
3
4
5 #include "misc.h"
6
7 #include "dlgsetting.h"
8 #include "errormessage.h"
9 #include "mayu.h"
10 #include "mayurc.h"
11 #include "registry.h"
12 #include "setting.h"
13 #include "windowstool.h"
14 #include "vkeytable.h"
15 #include "array.h"
16
17 #include <algorithm>
18 #include <fstream>
19 #include <iomanip>
20 #include <sys/stat.h>
21
22
23 namespace Event
24 {
25   Key prefixed(_T("prefixed"));
26   Key before_key_down(_T("before-key-down"));
27   Key after_key_up(_T("after-key-up"));
28   Key *events[] =
29   {
30     &prefixed,
31     &before_key_down,
32     &after_key_up,
33     NULL,
34   };
35 }
36
37
38 // get mayu filename
39 static bool getFilenameFromRegistry(
40   tstringi *o_name, tstringi *o_filename, Setting::Symbols *o_symbols)
41 {
42   Registry reg(MAYU_REGISTRY_ROOT);
43   int index;
44   reg.read(_T(".mayuIndex"), &index, 0);
45   _TCHAR buf[100];
46   _sntprintf(buf, NUMBER_OF(buf), _T(".mayu%d"), index);
47
48   tstringi entry;
49   if (!reg.read(buf, &entry))
50     return false;
51   
52   tregex getFilename(_T("^([^;]*);([^;]*);(.*)$"));
53   tsmatch getFilenameResult;
54   if (!boost::regex_match(entry, getFilenameResult, getFilename))
55     return false;
56   
57   if (o_name)
58     *o_name = getFilenameResult.str(1);
59   if (o_filename)
60     *o_filename = getFilenameResult.str(2);
61   if (o_symbols)
62   {
63     tstringi symbols = getFilenameResult.str(3);
64     tregex symbol(_T("-D([^;]*)(.*)$"));
65     tsmatch symbolResult;
66     while (boost::regex_search(symbols, symbolResult, symbol))
67     {
68       o_symbols->insert(symbolResult.str(1));
69       symbols = symbolResult.str(2);
70     }
71   }
72   return true;
73 }
74
75
76 // get home directory path
77 void getHomeDirectories(HomeDirectories *o_pathes)
78 {
79   tstringi filename;
80   if (getFilenameFromRegistry(NULL, &filename, NULL) &&
81       !filename.empty())
82   {
83     tregex getPath(_T("^(.*[/\\\\])[^/\\\\]*$"));
84     tsmatch getPathResult;
85     if (boost::regex_match(filename, getPathResult, getPath))
86       o_pathes->push_back(getPathResult.str(1));
87   }
88   
89   const _TCHAR *home = _tgetenv(_T("HOME"));
90   if (home)
91     o_pathes->push_back(home);
92
93   const _TCHAR *homedrive = _tgetenv(_T("HOMEDRIVE"));
94   const _TCHAR *homepath = _tgetenv(_T("HOMEPATH"));
95   if (homedrive && homepath)
96     o_pathes->push_back(tstringi(homedrive) + homepath);
97   
98   const _TCHAR *userprofile = _tgetenv(_T("USERPROFILE"));
99   if (userprofile)
100     o_pathes->push_back(userprofile);
101   
102   _TCHAR buf[GANA_MAX_PATH];
103   DWORD len = GetCurrentDirectory(NUMBER_OF(buf), buf);
104   if (0 < len && len < NUMBER_OF(buf))
105     o_pathes->push_back(buf);
106
107   if (GetModuleFileName(GetModuleHandle(NULL), buf, NUMBER_OF(buf)))
108     o_pathes->push_back(pathRemoveFileSpec(buf));
109 }
110
111
112 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113 // SettingLoader
114
115
116 // is there no more tokens ?
117 bool SettingLoader::isEOL()
118 {
119   return m_ti == m_tokens.end();
120 }
121
122
123 // get next token
124 Token *SettingLoader::getToken()
125 {
126   if (isEOL())
127     throw ErrorMessage() << _T("too few words.");
128   return &*(m_ti ++);
129 }
130
131   
132 // look next token
133 Token *SettingLoader::lookToken()
134 {
135   if (isEOL())
136     throw ErrorMessage() << _T("too few words.");
137   return &*m_ti;
138 }
139
140
141 // argument "("
142 bool SettingLoader::getOpenParen(bool i_doesThrow, const _TCHAR *i_name)
143 {
144   if (!isEOL() && lookToken()->isOpenParen())
145   {
146     getToken();
147     return true;
148   }
149   if (i_doesThrow)
150     throw ErrorMessage() << _T("there must be `(' after `&")
151                          << i_name << _T("'.");
152   return false;
153 }
154
155
156 // argument ")"
157 bool SettingLoader::getCloseParen(bool i_doesThrow, const _TCHAR *i_name)
158 {
159   if (!isEOL() && lookToken()->isCloseParen())
160   {
161     getToken();
162     return true;
163   }
164   if (i_doesThrow)
165     throw ErrorMessage() << _T("`&")  << i_name
166                          << _T("': too many arguments.");
167   return false;
168 }
169
170
171 // argument ","
172 bool SettingLoader::getComma(bool i_doesThrow, const _TCHAR *i_name)
173 {
174   if (!isEOL() && lookToken()->isComma())
175   {
176     getToken();
177     return true;
178   }
179   if (i_doesThrow)
180     throw ErrorMessage() << _T("`&")  << i_name
181                          << _T("': comma expected.");
182   return false;
183 }
184
185
186 // <INCLUDE>
187 void SettingLoader::load_INCLUDE()
188 {
189   SettingLoader loader(m_soLog, m_log);
190   loader.m_defaultAssignModifier = m_defaultAssignModifier;
191   loader.m_defaultKeySeqModifier = m_defaultKeySeqModifier;
192   if (!loader.load(m_setting, (*getToken()).getString()))
193     m_isThereAnyError = true;
194 }
195
196
197 // <SCAN_CODES>
198 void SettingLoader::load_SCAN_CODES(Key *o_key)
199 {
200   for (int j = 0; j < Key::MAX_SCAN_CODES_SIZE && !isEOL(); ++ j)
201   {
202     ScanCode sc;
203     sc.m_flags = 0;
204     while (true)
205     {
206       Token *t = getToken();
207       if (t->isNumber())
208       {
209         sc.m_scan = (u_char)t->getNumber();
210         o_key->addScanCode(sc);
211         break;
212       }
213       if      (*t == _T("E0-")) sc.m_flags |= ScanCode::E0;
214       else if (*t == _T("E1-")) sc.m_flags |= ScanCode::E1;
215       else  throw ErrorMessage() << _T("`") << *t
216                                  << _T("': invalid modifier.");
217     }
218   }
219 }
220
221
222 // <DEFINE_KEY>
223 void SettingLoader::load_DEFINE_KEY()
224 {
225   Token *t = getToken();
226   Key key;
227       
228   // <KEY_NAMES>
229   if (*t == _T('('))
230   {
231     key.addName(getToken()->getString());
232     while (t = getToken(), *t != _T(')'))
233       key.addName(t->getString());
234     if (*getToken() != _T("="))
235       throw ErrorMessage() << _T("there must be `=' after `)'.");
236   }
237   else
238   {
239     key.addName(t->getString());
240     while (t = getToken(), *t != _T("="))
241       key.addName(t->getString());
242   }
243
244   load_SCAN_CODES(&key);
245   m_setting->m_keyboard.addKey(key);
246 }
247
248
249 // <DEFINE_MODIFIER>
250 void SettingLoader::load_DEFINE_MODIFIER()
251 {
252   Token *t = getToken();
253   Modifier::Type mt;
254   if      (*t == _T("shift")  ) mt = Modifier::Type_Shift;
255   else if (*t == _T("alt")     ||
256            *t == _T("meta")    ||
257            *t == _T("menu")   ) mt = Modifier::Type_Alt;
258   else if (*t == _T("control") ||
259            *t == _T("ctrl")   ) mt = Modifier::Type_Control;
260   else if (*t == _T("windows") ||
261            *t == _T("win")    ) mt = Modifier::Type_Windows;
262   else throw ErrorMessage() << _T("`") << *t
263                             << _T("': invalid modifier name.");
264     
265   if (*getToken() != _T("="))
266     throw ErrorMessage() << _T("there must be `=' after modifier name.");
267     
268   while (!isEOL())
269   {
270     t = getToken();
271     Key *key =
272       m_setting->m_keyboard.searchKeyByNonAliasName(t->getString());
273     if (!key)
274       throw ErrorMessage() << _T("`") << *t << _T("': invalid key name.");
275     m_setting->m_keyboard.addModifier(mt, key);
276   }
277 }
278
279
280 // <DEFINE_SYNC_KEY>
281 void SettingLoader::load_DEFINE_SYNC_KEY()
282 {
283   Key *key = m_setting->m_keyboard.getSyncKey();
284   key->initialize();
285   key->addName(_T("sync"));
286   
287   if (*getToken() != _T("="))
288     throw ErrorMessage() << _T("there must be `=' after `sync'.");
289   
290   load_SCAN_CODES(key);
291 }
292
293
294 // <DEFINE_ALIAS>
295 void SettingLoader::load_DEFINE_ALIAS()
296 {
297   Token *name = getToken();
298   
299   if (*getToken() != _T("="))
300     throw ErrorMessage() << _T("there must be `=' after `alias'.");
301
302   Token *t = getToken();
303   Key *key = m_setting->m_keyboard.searchKeyByNonAliasName(t->getString());
304   if (!key)
305     throw ErrorMessage() << _T("`") << *t << _T("': invalid key name.");
306   m_setting->m_keyboard.addAlias(name->getString(), key);
307 }
308
309
310 // <DEFINE_SUBSTITUTE>
311 void SettingLoader::load_DEFINE_SUBSTITUTE()
312 {
313   typedef std::list<ModifiedKey> AssignedKeys;
314   AssignedKeys assignedKeys;
315   do
316   {
317     ModifiedKey mkey;
318     mkey.m_modifier =
319       load_MODIFIER(Modifier::Type_ASSIGN, m_defaultAssignModifier);
320     mkey.m_key = load_KEY_NAME();
321     assignedKeys.push_back(mkey);
322   } while (!(*lookToken() == _T("=>") || *lookToken() == _T("=")));
323   getToken();
324   
325   KeySeq *keySeq = load_KEY_SEQUENCE(_T(""), false, Modifier::Type_ASSIGN);
326   ModifiedKey mkey = keySeq->getFirstModifiedKey();
327   if (!mkey.m_key)
328     throw ErrorMessage() << _T("no key is specified for substitute.");
329   
330   for (AssignedKeys::iterator i = assignedKeys.begin();
331        i != assignedKeys.end(); ++ i)
332     m_setting->m_keyboard.addSubstitute(*i, mkey);
333 }
334
335
336 // <DEFINE_OPTION>
337 void SettingLoader::load_DEFINE_OPTION()
338 {
339   Token *t = getToken();
340   if (*t == _T("KL-")) {
341     if (*getToken() != _T("=")) {
342       throw ErrorMessage() << _T("there must be `=' after `def option KL-'.");
343     }
344
345     load_ARGUMENT(&m_setting->m_correctKanaLockHandling);
346     
347   } else if (*t == _T("delay-of")) {
348     if (*getToken() != _T("!!!")) {
349       throw ErrorMessage()
350         << _T("there must be `!!!' after `def option delay-of'.");
351     }
352     
353     if (*getToken() != _T("=")) {
354       throw ErrorMessage()
355         << _T("there must be `=' after `def option delay-of !!!'.");
356     }
357     
358     load_ARGUMENT(&m_setting->m_oneShotRepeatableDelay);
359     
360   } else if (*t == _T("sts4mayu")) {
361     if (*getToken() != _T("=")) {
362       throw ErrorMessage()
363         << _T("there must be `=' after `def option sts4mayu'.");
364     }
365     
366     load_ARGUMENT(&m_setting->m_sts4mayu);
367     
368   } else if (*t == _T("cts4mayu")) {
369     if (*getToken() != _T("=")) {
370       throw ErrorMessage()
371         << _T("there must be `=' after `def option cts4mayu'.");
372     }
373     
374     load_ARGUMENT(&m_setting->m_cts4mayu);
375     
376   } else {
377     throw ErrorMessage() << _T("syntax error `def option ") << *t << _T("'.");
378   }
379 }
380
381
382
383 // <KEYBOARD_DEFINITION>
384 void SettingLoader::load_KEYBOARD_DEFINITION()
385 {
386   Token *t = getToken();
387     
388   // <DEFINE_KEY>
389   if (*t == _T("key")) load_DEFINE_KEY();
390
391   // <DEFINE_MODIFIER>
392   else if (*t == _T("mod")) load_DEFINE_MODIFIER();
393   
394   // <DEFINE_SYNC_KEY>
395   else if (*t == _T("sync")) load_DEFINE_SYNC_KEY();
396   
397   // <DEFINE_ALIAS>
398   else if (*t == _T("alias")) load_DEFINE_ALIAS();
399   
400   // <DEFINE_SUBSTITUTE>
401   else if (*t == _T("subst")) load_DEFINE_SUBSTITUTE();
402
403   // <DEFINE_OPTION>
404   else if (*t == _T("option")) load_DEFINE_OPTION();
405   
406   //
407   else throw ErrorMessage() << _T("syntax error `") << *t << _T("'.");
408 }
409
410
411 // <..._MODIFIER>
412 Modifier SettingLoader::load_MODIFIER(
413   Modifier::Type i_mode, Modifier i_modifier, Modifier::Type *o_mode)
414 {
415   if (o_mode)
416     *o_mode = Modifier::Type_begin;
417   
418   Modifier isModifierSpecified;
419   enum { PRESS, RELEASE, DONTCARE } flag = PRESS;
420
421   int i;
422   for (i = i_mode; i < Modifier::Type_ASSIGN; ++ i)
423   {
424     i_modifier.dontcare(Modifier::Type(i));
425     isModifierSpecified.on(Modifier::Type(i));
426   }
427   
428   Token *t = NULL;
429   
430   continue_loop:
431   while (!isEOL())
432   {
433     t = lookToken();
434
435     const static struct { const _TCHAR *m_s; Modifier::Type m_mt; } map[] =
436     {
437       // <BASIC_MODIFIER>
438       { _T("S-"),  Modifier::Type_Shift },
439       { _T("A-"),  Modifier::Type_Alt },
440       { _T("M-"),  Modifier::Type_Alt },
441       { _T("C-"),  Modifier::Type_Control },
442       { _T("W-"),  Modifier::Type_Windows },
443       // <KEYSEQ_MODIFIER>
444       { _T("U-"),  Modifier::Type_Up },
445       { _T("D-"),  Modifier::Type_Down },
446       // <ASSIGN_MODIFIER>
447       { _T("R-"),  Modifier::Type_Repeat },
448       { _T("IL-"), Modifier::Type_ImeLock },
449       { _T("IC-"), Modifier::Type_ImeComp },
450       { _T("I-"),  Modifier::Type_ImeComp },
451       { _T("NL-"), Modifier::Type_NumLock },
452       { _T("CL-"), Modifier::Type_CapsLock },
453       { _T("SL-"), Modifier::Type_ScrollLock },
454       { _T("KL-"), Modifier::Type_KanaLock },
455       { _T("MAX-"), Modifier::Type_Maximized },
456       { _T("MIN-"), Modifier::Type_Minimized },
457       { _T("MMAX-"), Modifier::Type_MdiMaximized },
458       { _T("MMIN-"), Modifier::Type_MdiMinimized },
459       { _T("T-"), Modifier::Type_Touchpad },
460       { _T("TS-"), Modifier::Type_TouchpadSticky },
461       { _T("M0-"), Modifier::Type_Mod0 },
462       { _T("M1-"), Modifier::Type_Mod1 },
463       { _T("M2-"), Modifier::Type_Mod2 },
464       { _T("M3-"), Modifier::Type_Mod3 },
465       { _T("M4-"), Modifier::Type_Mod4 },
466       { _T("M5-"), Modifier::Type_Mod5 },
467       { _T("M6-"), Modifier::Type_Mod6 },
468       { _T("M7-"), Modifier::Type_Mod7 },
469       { _T("M8-"), Modifier::Type_Mod8 },
470       { _T("M9-"), Modifier::Type_Mod9 },
471       { _T("L0-"), Modifier::Type_Lock0 },
472       { _T("L1-"), Modifier::Type_Lock1 },
473       { _T("L2-"), Modifier::Type_Lock2 },
474       { _T("L3-"), Modifier::Type_Lock3 },
475       { _T("L4-"), Modifier::Type_Lock4 },
476       { _T("L5-"), Modifier::Type_Lock5 },
477       { _T("L6-"), Modifier::Type_Lock6 },
478       { _T("L7-"), Modifier::Type_Lock7 },
479       { _T("L8-"), Modifier::Type_Lock8 },
480       { _T("L9-"), Modifier::Type_Lock9 },
481     };
482
483     for (int i = 0; i < NUMBER_OF(map); ++ i)
484       if (*t == map[i].m_s)
485       {
486         getToken();
487         Modifier::Type mt = map[i].m_mt;
488         if (static_cast<int>(i_mode) <= static_cast<int>(mt))
489           throw ErrorMessage() << _T("`") << *t
490                                << _T("': invalid modifier at this context.");
491         switch (flag)
492         {
493           case PRESS: i_modifier.press(mt); break;
494           case RELEASE: i_modifier.release(mt); break;
495           case DONTCARE: i_modifier.dontcare(mt); break;
496         }
497         isModifierSpecified.on(mt);
498         flag = PRESS;
499         
500         if (o_mode && *o_mode < mt)
501         {
502           if (mt < Modifier::Type_BASIC)
503             *o_mode = Modifier::Type_BASIC;
504           else if (mt < Modifier::Type_KEYSEQ)
505             *o_mode = Modifier::Type_KEYSEQ;
506           else if (mt < Modifier::Type_ASSIGN)
507             *o_mode = Modifier::Type_ASSIGN;
508         }
509         goto continue_loop;
510       }
511       
512     if (*t == _T("*"))
513     {
514       getToken();
515       flag = DONTCARE;
516       continue;
517     }
518       
519     if (*t == _T("~"))
520     {
521       getToken();
522       flag = RELEASE;
523       continue;
524     }
525
526     break;
527   }
528   
529   for (i = Modifier::Type_begin; i != Modifier::Type_end; ++ i)
530     if (!isModifierSpecified.isOn(Modifier::Type(i)))
531       switch (flag)
532       {
533         case PRESS: break;
534         case RELEASE: i_modifier.release(Modifier::Type(i)); break;
535         case DONTCARE: i_modifier.dontcare(Modifier::Type(i)); break;
536       }
537
538   // fix up and down
539   bool isDontcareUp   = i_modifier.isDontcare(Modifier::Type_Up);
540   bool isDontcareDown = i_modifier.isDontcare(Modifier::Type_Down);
541   bool isOnUp         = i_modifier.isOn(Modifier::Type_Up);
542   bool isOnDown       = i_modifier.isOn(Modifier::Type_Down);
543   if (isDontcareUp && isDontcareDown)
544     ;
545   else if (isDontcareUp)
546     i_modifier.on(Modifier::Type_Up, !isOnDown);
547   else if (isDontcareDown)
548     i_modifier.on(Modifier::Type_Down, !isOnUp);
549   else if (isOnUp == isOnDown)
550   {
551     i_modifier.dontcare(Modifier::Type_Up);
552     i_modifier.dontcare(Modifier::Type_Down);
553   }
554
555   // fix repeat
556   if (!isModifierSpecified.isOn(Modifier::Type_Repeat))
557     i_modifier.dontcare(Modifier::Type_Repeat);
558   return i_modifier;
559 }
560
561
562 // <KEY_NAME>
563 Key *SettingLoader::load_KEY_NAME()
564 {
565   Token *t = getToken();
566   Key *key = m_setting->m_keyboard.searchKey(t->getString());
567   if (!key)
568     throw ErrorMessage() << _T("`") << *t << _T("': invalid key name.");
569   return key;
570 }
571
572
573 // <KEYMAP_DEFINITION>
574 void SettingLoader::load_KEYMAP_DEFINITION(const Token *i_which)
575 {
576   Keymap::Type type = Keymap::Type_keymap;
577   Token *name = getToken();     // <KEYMAP_NAME>
578   tstringi windowClassName;
579   tstringi windowTitleName;
580   KeySeq *keySeq = NULL;
581   Keymap *parentKeymap = NULL;
582   bool isKeymap2 = false;
583   bool doesLoadDefaultKeySeq = false;
584
585   if (!isEOL())
586   {
587     Token *t = lookToken();
588     if (*i_which == _T("window"))       // <WINDOW>
589     {
590       if (t->isOpenParen())
591         // "(" <WINDOW_CLASS_NAME> "&&" <WINDOW_TITLE_NAME> ")"
592         // "(" <WINDOW_CLASS_NAME> "||" <WINDOW_TITLE_NAME> ")"
593       {
594         getToken();
595         windowClassName = getToken()->getRegexp();
596         t = getToken();
597         if (*t == _T("&&"))
598           type = Keymap::Type_windowAnd;
599         else if (*t == _T("||"))
600           type = Keymap::Type_windowOr;
601         else
602           throw ErrorMessage() << _T("`") << *t << _T("': unknown operator.");
603         windowTitleName = getToken()->getRegexp();
604         if (!getToken()->isCloseParen())
605           throw ErrorMessage() << _T("there must be `)'.");
606       }
607       else if (t->isRegexp())   // <WINDOW_CLASS_NAME>
608       {
609         getToken();
610         type = Keymap::Type_windowAnd;
611         windowClassName = t->getRegexp();
612       }
613     }
614     else if (*i_which == _T("keymap"))
615       ;
616     else if (*i_which == _T("keymap2"))
617       isKeymap2 = true;
618     else
619       ASSERT(false);
620     
621     if (!isEOL())
622       doesLoadDefaultKeySeq = true;
623   }
624
625   m_currentKeymap = m_setting->m_keymaps.add(
626     Keymap(type, name->getString(), windowClassName, windowTitleName,
627            NULL, NULL));
628
629   if (doesLoadDefaultKeySeq)
630   {
631     Token *t = lookToken();
632     // <KEYMAP_PARENT>
633     if (*t == _T(":"))
634     {
635       getToken();
636       t = getToken();
637       parentKeymap = m_setting->m_keymaps.searchByName(t->getString());
638       if (!parentKeymap)
639         throw ErrorMessage() << _T("`") << *t
640                              << _T("': unknown keymap name.");
641     }
642     if (!isEOL())
643     {
644       t = getToken();
645       if (!(*t == _T("=>") || *t == _T("=")))
646         throw ErrorMessage() << _T("`") << *t << _T("': syntax error.");
647       keySeq = SettingLoader::load_KEY_SEQUENCE();
648     }
649   }
650   if (keySeq == NULL)
651   {
652     FunctionData *fd;
653     if (type == Keymap::Type_keymap && !isKeymap2)
654       fd = createFunctionData(_T("KeymapParent"));
655     else if (type == Keymap::Type_keymap && !isKeymap2)
656       fd = createFunctionData(_T("Undefined"));
657     else // (type == Keymap::Type_windowAnd || type == Keymap::Type_windowOr)
658       fd = createFunctionData(_T("KeymapParent"));
659     ASSERT( fd );
660     keySeq = m_setting->m_keySeqs.add(
661       KeySeq(name->getString()).add(ActionFunction(fd)));
662   }
663
664   m_currentKeymap->setIfNotYet(keySeq, parentKeymap);
665 }
666
667
668 // &lt;ARGUMENT&gt;
669 void SettingLoader::load_ARGUMENT(bool *o_arg)
670 {
671   *o_arg = !(*getToken() == _T("false"));
672 }
673
674
675 // &lt;ARGUMENT&gt;
676 void SettingLoader::load_ARGUMENT(int *o_arg)
677 {
678   *o_arg = getToken()->getNumber();
679 }
680
681
682 // &lt;ARGUMENT&gt;
683 void SettingLoader::load_ARGUMENT(unsigned int *o_arg)
684 {
685   *o_arg = getToken()->getNumber();
686 }
687
688
689 // &lt;ARGUMENT&gt;
690 void SettingLoader::load_ARGUMENT(long *o_arg)
691 {
692   *o_arg = getToken()->getNumber();
693 }
694
695
696 // &lt;ARGUMENT&gt;
697 void SettingLoader::load_ARGUMENT(tstringq *o_arg)
698 {
699   *o_arg = getToken()->getString();
700 }
701
702
703 // &lt;ARGUMENT&gt;
704 void SettingLoader::load_ARGUMENT(std::list<tstringq> *o_arg)
705 {
706   while (true)
707   {
708     if (!lookToken()->isString())
709       return;
710     o_arg->push_back(getToken()->getString());
711     
712     if (!lookToken()->isComma())
713       return;
714     getToken();
715   }
716 }
717
718
719 // &lt;ARGUMENT&gt;
720 void SettingLoader::load_ARGUMENT(tregex *o_arg)
721 {
722   *o_arg = getToken()->getRegexp();
723 }
724
725
726 // &lt;ARGUMENT_VK&gt;
727 void SettingLoader::load_ARGUMENT(VKey *o_arg)
728 {
729   Token *t = getToken();
730   int vkey = 0;
731   while (true)
732   {
733     if (t->isNumber()) { vkey |= static_cast<BYTE>(t->getNumber()); break; }
734     else if (*t == _T("E-")) vkey |= VKey_extended;
735     else if (*t == _T("U-")) vkey |= VKey_released;
736     else if (*t == _T("D-")) vkey |= VKey_pressed;
737     else
738     {
739       const VKeyTable *vkt;
740       for (vkt = g_vkeyTable; vkt->m_name; ++ vkt)
741         if (*t == vkt->m_name)
742           break;
743       if (!vkt->m_name)
744         throw ErrorMessage() << _T("`") << *t
745                              << _T("': unknown virtual key name.");
746       vkey |= vkt->m_code;
747       break;
748     }
749     t = getToken();
750   }
751   if (!(vkey & VKey_released) && !(vkey & VKey_pressed))
752     vkey |= VKey_released | VKey_pressed;
753   *o_arg = static_cast<VKey>(vkey);
754 }
755
756
757 // &lt;ARGUMENT_WINDOW&gt;
758 void SettingLoader::load_ARGUMENT(ToWindowType *o_arg)
759 {
760   Token *t = getToken();
761   if (t->isNumber())
762   {
763     if (ToWindowType_toBegin <= t->getNumber())
764     {
765       *o_arg = static_cast<ToWindowType>(t->getNumber());
766       return;
767     }
768   }
769   else if (getTypeValue(o_arg, t->getString()))
770     return;
771   throw ErrorMessage() << _T("`") << *t << _T("': invalid target window.");
772 }
773
774
775 // &lt;ARGUMENT&gt;
776 void SettingLoader::load_ARGUMENT(GravityType *o_arg)
777 {
778   Token *t = getToken();
779   if (getTypeValue(o_arg, t->getString()))
780     return;
781   throw ErrorMessage() << _T("`") << *t << _T("': unknown gravity symbol.");
782 }
783
784
785 // &lt;ARGUMENT&gt;
786 void SettingLoader::load_ARGUMENT(MouseHookType *o_arg)
787 {
788   Token *t = getToken();
789   if (getTypeValue(o_arg, t->getString()))
790     return;
791   throw ErrorMessage() << _T("`") << *t << _T("': unknown MouseHookType symbol.");
792 }
793
794
795 // &lt;ARGUMENT&gt;
796 void SettingLoader::load_ARGUMENT(MayuDialogType *o_arg)
797 {
798   Token *t = getToken();
799   if (getTypeValue(o_arg, t->getString()))
800     return;
801   throw ErrorMessage() << _T("`") << *t << _T("': unknown dialog box.");
802 }
803
804
805 // &lt;ARGUMENT_LOCK&gt;
806 void SettingLoader::load_ARGUMENT(ModifierLockType *o_arg)
807 {
808   Token *t = getToken();
809   if (getTypeValue(o_arg, t->getString()))
810     return;
811   throw ErrorMessage() << _T("`") << *t << _T("': unknown lock name.");
812 }
813
814
815 // &lt;ARGUMENT_LOCK&gt;
816 void SettingLoader::load_ARGUMENT(ToggleType *o_arg)
817 {
818   Token *t = getToken();
819   if (getTypeValue(o_arg, t->getString()))
820     return;
821   throw ErrorMessage() << _T("`") << *t << _T("': unknown toggle name.");
822 }
823
824
825 // &lt;ARGUMENT_SHOW_WINDOW&gt;
826 void SettingLoader::load_ARGUMENT(ShowCommandType *o_arg)
827 {
828   Token *t = getToken();
829   if (getTypeValue(o_arg, t->getString()))
830     return;
831   throw ErrorMessage() << _T("`") << *t << _T("': unknown show command.");
832 }
833
834
835 // &lt;ARGUMENT_TARGET_WINDOW&gt;
836 void SettingLoader::load_ARGUMENT(TargetWindowType *o_arg)
837 {
838   Token *t = getToken();
839   if (getTypeValue(o_arg, t->getString()))
840     return;
841   throw ErrorMessage() << _T("`") << *t
842                        << _T("': unknown target window type.");
843 }
844
845
846 // &lt;bool&gt;
847 void SettingLoader::load_ARGUMENT(BooleanType *o_arg)
848 {
849   Token *t = getToken();
850   if (getTypeValue(o_arg, t->getString()))
851     return;
852   throw ErrorMessage() << _T("`") << *t << _T("': must be true or false.");
853 }
854
855
856 // &lt;ARGUMENT&gt;
857 void SettingLoader::load_ARGUMENT(LogicalOperatorType *o_arg)
858 {
859   Token *t = getToken();
860   if (getTypeValue(o_arg, t->getString()))
861     return;
862   throw ErrorMessage() << _T("`") << *t << _T("': must be 'or' or 'and'.");
863 }
864
865
866 // &lt;ARGUMENT&gt;
867 void SettingLoader::load_ARGUMENT(Modifier *o_arg)
868 {
869   Modifier modifier;
870   for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i)
871     modifier.dontcare(static_cast<Modifier::Type>(i));
872   *o_arg = load_MODIFIER(Modifier::Type_ASSIGN, modifier);
873 }
874
875
876 // &lt;ARGUMENT&gt;
877 void SettingLoader::load_ARGUMENT(const Keymap **o_arg)
878 {
879   Token *t = getToken();
880   const Keymap *&keymap = *o_arg;
881   keymap = m_setting->m_keymaps.searchByName(t->getString());
882   if (!keymap)
883     throw ErrorMessage() << _T("`") << *t << _T("': unknown keymap name.");
884 }
885
886
887 // &lt;ARGUMENT&gt;
888 void SettingLoader::load_ARGUMENT(const KeySeq **o_arg)
889 {
890   Token *t = getToken();
891   const KeySeq *&keySeq = *o_arg;
892   if (t->isOpenParen())
893   {
894     keySeq = load_KEY_SEQUENCE(_T(""), true);
895     getToken(); // close paren
896   }
897   else if (*t == _T("$"))
898   {
899     t = getToken();
900     keySeq = m_setting->m_keySeqs.searchByName(t->getString());
901     if (!keySeq)
902       throw ErrorMessage() << _T("`$") << *t << _T("': unknown keyseq name.");
903   }
904   else
905     throw ErrorMessage() << _T("`") << *t << _T("': it is not keyseq.");
906 }
907
908
909 // &lt;ARGUMENT&gt;
910 void SettingLoader::load_ARGUMENT(StrExprArg *o_arg)
911 {
912   Token *t = getToken();
913   StrExprArg::Type type = StrExprArg::Literal;
914   if (*t == _T("$") && t->isQuoted() == false
915       && lookToken()->getType() == Token::Type_string)
916   {
917     type = StrExprArg::Builtin;
918     t = getToken();
919   }
920   *o_arg = StrExprArg(t->getString(), type);
921 }
922
923
924 // &lt;ARGUMENT&gt;
925 void SettingLoader::load_ARGUMENT(WindowMonitorFromType *o_arg)
926 {
927   Token *t = getToken();
928   if (getTypeValue(o_arg, t->getString()))
929     return;
930   throw ErrorMessage() << _T("`") << *t
931                        << _T("': unknown monitor from type.");
932 }
933
934
935 // <KEY_SEQUENCE>
936 KeySeq *SettingLoader::load_KEY_SEQUENCE(
937   const tstringi &i_name, bool i_isInParen, Modifier::Type i_mode)
938 {
939   KeySeq keySeq(i_name);
940   while (!isEOL())
941   {
942     Modifier::Type mode;
943     Modifier modifier = load_MODIFIER(i_mode, m_defaultKeySeqModifier, &mode);
944     keySeq.setMode(mode);
945     Token *t = lookToken();
946     if (t->isCloseParen() && i_isInParen)
947       break;
948     else if (t->isOpenParen())
949     {
950       getToken(); // open paren
951       KeySeq *ks = load_KEY_SEQUENCE(_T(""), true, i_mode);
952       getToken(); // close paren
953       keySeq.add(ActionKeySeq(ks));
954     }
955     else if (*t == _T("$")) // <KEYSEQ_NAME>
956     {
957       getToken();
958       t = getToken();
959       KeySeq *ks = m_setting->m_keySeqs.searchByName(t->getString());
960       if (ks == NULL)
961         throw ErrorMessage() << _T("`$") << *t
962                              << _T("': unknown keyseq name.");
963       if (!ks->isCorrectMode(i_mode))
964         throw ErrorMessage()
965           << _T("`$") << *t
966           << _T("': Some of R-, IL-, IC-, NL-, CL-, SL-, KL-, MAX-, MIN-, MMAX-, MMIN-, T-, TS-, M0...M9- and L0...L9- are used in the keyseq.  They are prohibited in this context.");
967       keySeq.setMode(ks->getMode());
968       keySeq.add(ActionKeySeq(ks));
969     }
970     else if (*t == _T("&")) // <FUNCTION_NAME>
971     {
972       getToken();
973       t = getToken();
974       
975       // search function
976       ActionFunction af(createFunctionData(t->getString()), modifier);
977       if (af.m_functionData == NULL)
978         throw ErrorMessage() << _T("`&") << *t
979                              << _T("': unknown function name.");
980       af.m_functionData->load(this);
981       keySeq.add(af);
982     }
983     else // <KEYSEQ_MODIFIED_KEY_NAME>
984     {
985       ModifiedKey mkey;
986       mkey.m_modifier = modifier;
987       mkey.m_key = load_KEY_NAME();
988       keySeq.add(ActionKey(mkey));
989     }
990   }
991   return m_setting->m_keySeqs.add(keySeq);
992 }
993
994
995 // <KEY_ASSIGN>
996 void SettingLoader::load_KEY_ASSIGN()
997 {
998   typedef std::list<ModifiedKey> AssignedKeys;
999   AssignedKeys assignedKeys;
1000   
1001   ModifiedKey mkey;
1002   mkey.m_modifier =
1003     load_MODIFIER(Modifier::Type_ASSIGN, m_defaultAssignModifier);
1004   if (*lookToken() == _T("="))
1005   {
1006     getToken();
1007     m_defaultKeySeqModifier = load_MODIFIER(Modifier::Type_KEYSEQ,
1008                                             m_defaultKeySeqModifier);
1009     m_defaultAssignModifier = mkey.m_modifier;
1010     return;
1011   }
1012   
1013   while (true)
1014   {
1015     mkey.m_key = load_KEY_NAME();
1016     assignedKeys.push_back(mkey);
1017     if (*lookToken() == _T("=>") || *lookToken() == _T("="))
1018       break;
1019     mkey.m_modifier =
1020       load_MODIFIER(Modifier::Type_ASSIGN, m_defaultAssignModifier);
1021   }
1022   getToken();
1023
1024   ASSERT(m_currentKeymap);
1025   KeySeq *keySeq = load_KEY_SEQUENCE();
1026   for (AssignedKeys::iterator i = assignedKeys.begin();
1027        i != assignedKeys.end(); ++ i)
1028     m_currentKeymap->addAssignment(*i, keySeq);
1029 }
1030
1031
1032 // <EVENT_ASSIGN>
1033 void SettingLoader::load_EVENT_ASSIGN()
1034 {
1035   std::list<ModifiedKey> assignedKeys;
1036
1037   ModifiedKey mkey;
1038   mkey.m_modifier.dontcare();                   //set all modifiers to dontcare
1039   
1040   Token *t = getToken();
1041   Key **e;
1042   for (e = Event::events; *e; ++ e)
1043     if (*t == (*e)->getName())
1044     {
1045       mkey.m_key = *e;
1046       break;
1047     }
1048   if (!*e)
1049     throw ErrorMessage() << _T("`") << *t << _T("': invalid event name.");
1050
1051   t = getToken();
1052   if (!(*t == _T("=>") || *t == _T("=")))
1053     throw ErrorMessage() << _T("`=' is expected.");
1054
1055   ASSERT(m_currentKeymap);
1056   KeySeq *keySeq = load_KEY_SEQUENCE();
1057   m_currentKeymap->addAssignment(mkey, keySeq);
1058 }
1059
1060
1061 // <MODIFIER_ASSIGNMENT>
1062 void SettingLoader::load_MODIFIER_ASSIGNMENT()
1063 {
1064   // <MODIFIER_NAME>
1065   Token *t = getToken();
1066   Modifier::Type mt;
1067
1068   while (true)
1069   {
1070     Keymap::AssignMode am = Keymap::AM_notModifier;
1071     if      (*t == _T("!")  ) am = Keymap::AM_true, t = getToken();
1072     else if (*t == _T("!!") ) am = Keymap::AM_oneShot, t = getToken();
1073     else if (*t == _T("!!!")) am = Keymap::AM_oneShotRepeatable, t = getToken();
1074     
1075     if      (*t == _T("shift")) mt = Modifier::Type_Shift;
1076     else if (*t == _T("alt")  ||
1077              *t == _T("meta") ||
1078              *t == _T("menu") ) mt = Modifier::Type_Alt;
1079     else if (*t == _T("control") ||
1080              *t == _T("ctrl") ) mt = Modifier::Type_Control;
1081     else if (*t == _T("windows") ||
1082              *t == _T("win")  ) mt = Modifier::Type_Windows;
1083     else if (*t == _T("mod0") ) mt = Modifier::Type_Mod0;
1084     else if (*t == _T("mod1") ) mt = Modifier::Type_Mod1;
1085     else if (*t == _T("mod2") ) mt = Modifier::Type_Mod2;
1086     else if (*t == _T("mod3") ) mt = Modifier::Type_Mod3;
1087     else if (*t == _T("mod4") ) mt = Modifier::Type_Mod4;
1088     else if (*t == _T("mod5") ) mt = Modifier::Type_Mod5;
1089     else if (*t == _T("mod6") ) mt = Modifier::Type_Mod6;
1090     else if (*t == _T("mod7") ) mt = Modifier::Type_Mod7;
1091     else if (*t == _T("mod8") ) mt = Modifier::Type_Mod8;
1092     else if (*t == _T("mod9") ) mt = Modifier::Type_Mod9;
1093     else throw ErrorMessage() << _T("`") << *t
1094                               << _T("': invalid modifier name.");
1095
1096     if (am == Keymap::AM_notModifier)
1097       break;
1098     
1099     m_currentKeymap->addModifier(mt, Keymap::AO_overwrite, am, NULL);
1100     if (isEOL())
1101       return;
1102     t = getToken();
1103   }
1104   
1105   // <ASSIGN_OP>
1106   t = getToken();
1107   Keymap::AssignOperator ao;
1108   if      (*t == _T("=") ) ao = Keymap::AO_new;
1109   else if (*t == _T("+=")) ao = Keymap::AO_add;
1110   else if (*t == _T("-=")) ao = Keymap::AO_sub;
1111   else  throw ErrorMessage() << _T("`") << *t << _T("': is unknown operator.");
1112
1113   // <ASSIGN_MODE>? <KEY_NAME>
1114   while (!isEOL())
1115   {
1116     // <ASSIGN_MODE>? 
1117     t = getToken();
1118     Keymap::AssignMode am = Keymap::AM_normal;
1119     if      (*t == _T("!")  ) am = Keymap::AM_true, t = getToken();
1120     else if (*t == _T("!!") ) am = Keymap::AM_oneShot, t = getToken();
1121     else if (*t == _T("!!!")) am = Keymap::AM_oneShotRepeatable, t = getToken();
1122     
1123     // <KEY_NAME>
1124     Key *key = m_setting->m_keyboard.searchKey(t->getString());
1125     if (!key)
1126       throw ErrorMessage() << _T("`") << *t << _T("': invalid key name.");
1127
1128     // we can ignore warning C4701
1129     m_currentKeymap->addModifier(mt, ao, am, key);
1130     if (ao == Keymap::AO_new)
1131       ao = Keymap::AO_add;
1132   }
1133 }
1134
1135
1136 // <KEYSEQ_DEFINITION>
1137 void SettingLoader::load_KEYSEQ_DEFINITION()
1138 {
1139   if (*getToken() != _T("$"))
1140     throw ErrorMessage() << _T("there must be `$' after `keyseq'");
1141   Token *name = getToken();
1142   if (*getToken() != _T("="))
1143     throw ErrorMessage() << _T("there must be `=' after keyseq naem");
1144   load_KEY_SEQUENCE(name->getString(), false, Modifier::Type_ASSIGN);
1145 }
1146
1147
1148 // <DEFINE>
1149 void SettingLoader::load_DEFINE()
1150 {
1151   m_setting->m_symbols.insert(getToken()->getString());
1152 }
1153
1154
1155 // <IF>
1156 void SettingLoader::load_IF()
1157 {
1158   if (!getToken()->isOpenParen())
1159     throw ErrorMessage() << _T("there must be `(' after `if'.");
1160   Token *t = getToken(); // <SYMBOL> or !
1161   bool not = false;
1162   if (*t == _T("!"))
1163   {
1164     not = true;
1165     t = getToken(); // <SYMBOL>
1166   }
1167   
1168   bool doesSymbolExist = (m_setting->m_symbols.find(t->getString())
1169                           != m_setting->m_symbols.end());
1170   bool doesRead = ((doesSymbolExist && !not) ||
1171                    (!doesSymbolExist && not));
1172   if (0 < m_canReadStack.size())
1173     doesRead = doesRead && m_canReadStack.back();
1174   
1175   if (!getToken()->isCloseParen())
1176     throw ErrorMessage() << _T("there must be `)'.");
1177
1178   m_canReadStack.push_back(doesRead);
1179   if (!isEOL())
1180   {
1181     size_t len = m_canReadStack.size();
1182     load_LINE();
1183     if (len < m_canReadStack.size())
1184     {
1185       bool r = m_canReadStack.back();
1186       m_canReadStack.pop_back();
1187       m_canReadStack[len - 1] = r && doesRead;
1188     }
1189     else if (len == m_canReadStack.size())
1190       m_canReadStack.pop_back();
1191     else
1192       ; // `end' found
1193   }
1194 }
1195
1196
1197 // <ELSE> <ELSEIF>
1198 void SettingLoader::load_ELSE(bool i_isElseIf, const tstringi &i_token)
1199 {
1200   bool doesRead = !load_ENDIF(i_token);
1201   if (0 < m_canReadStack.size())
1202     doesRead = doesRead && m_canReadStack.back();
1203   m_canReadStack.push_back(doesRead);
1204   if (!isEOL())
1205   {
1206     size_t len = m_canReadStack.size();
1207     if (i_isElseIf)
1208       load_IF();
1209     else
1210       load_LINE();
1211     if (len < m_canReadStack.size())
1212     {
1213       bool r = m_canReadStack.back();
1214       m_canReadStack.pop_back();
1215       m_canReadStack[len - 1] = doesRead && r;
1216     }
1217     else if (len == m_canReadStack.size())
1218       m_canReadStack.pop_back();
1219     else
1220       ; // `end' found
1221   }
1222 }
1223
1224
1225 // <ENDIF>
1226 bool SettingLoader::load_ENDIF(const tstringi &i_token)
1227 {
1228   if (m_canReadStack.size() == 0)
1229     throw ErrorMessage() << _T("unbalanced `") << i_token << _T("'");
1230   bool r = m_canReadStack.back();
1231   m_canReadStack.pop_back();
1232   return r;
1233 }
1234
1235
1236 // <LINE>
1237 void SettingLoader::load_LINE()
1238 {
1239   Token *i_token = getToken();
1240
1241   // <COND_SYMBOL>
1242   if      (*i_token == _T("if") ||
1243            *i_token == _T("and")) load_IF();
1244   else if (*i_token == _T("else")) load_ELSE(false, i_token->getString());
1245   else if (*i_token == _T("elseif") ||
1246            *i_token == _T("elsif")  ||
1247            *i_token == _T("elif")   ||
1248            *i_token == _T("or")) load_ELSE(true, i_token->getString());
1249   else if (*i_token == _T("endif")) load_ENDIF(_T("endif"));
1250   else if (0 < m_canReadStack.size() && !m_canReadStack.back())
1251   {
1252     while (!isEOL())
1253       getToken();
1254   }
1255   else if (*i_token == _T("define")) load_DEFINE();
1256   // <INCLUDE>
1257   else if (*i_token == _T("include")) load_INCLUDE();
1258   // <KEYBOARD_DEFINITION>
1259   else if (*i_token == _T("def")) load_KEYBOARD_DEFINITION();
1260   // <KEYMAP_DEFINITION>
1261   else if (*i_token == _T("keymap")  ||
1262            *i_token == _T("keymap2") ||
1263            *i_token == _T("window")) load_KEYMAP_DEFINITION(i_token);
1264   // <KEY_ASSIGN>
1265   else if (*i_token == _T("key")) load_KEY_ASSIGN();
1266   // <EVENT_ASSIGN>
1267   else if (*i_token == _T("event")) load_EVENT_ASSIGN();
1268   // <MODIFIER_ASSIGNMENT>
1269   else if (*i_token == _T("mod")) load_MODIFIER_ASSIGNMENT();
1270   // <KEYSEQ_DEFINITION>
1271   else if (*i_token == _T("keyseq")) load_KEYSEQ_DEFINITION();
1272   else
1273     throw ErrorMessage() << _T("syntax error `") << *i_token << _T("'.");
1274 }
1275
1276   
1277 // prefix sort predicate used in load(const string &)
1278 static bool prefixSortPred(const tstringi &i_a, const tstringi &i_b)
1279 {
1280   return i_b.size() < i_a.size();
1281 }
1282
1283
1284 /*
1285   _UNICODE: read file (UTF-16 LE/BE, UTF-8, locale specific multibyte encoding)
1286   _MBCS: read file
1287 */
1288 bool readFile(tstring *o_data, const tstringi &i_filename)
1289 {
1290   // get size of file
1291 #if 0
1292   // bcc's _wstat cannot obtain file size
1293   struct _stat sbuf;
1294   if (_tstat(i_filename.c_str(), &sbuf) < 0 || sbuf.st_size == 0)
1295     return false;
1296 #else
1297   // so, we use _wstati64 for bcc
1298   struct stati64_t sbuf;
1299   if (_tstati64(i_filename.c_str(), &sbuf) < 0 || sbuf.st_size == 0)
1300     return false;
1301   // following check is needed to cast sbuf.st_size to size_t safely
1302   // this cast occurs because of above workaround for bcc
1303   if (sbuf.st_size > UINT_MAX)
1304     return false;
1305 #endif
1306   
1307   // open
1308   FILE *fp = _tfopen(i_filename.c_str(), _T("rb"));
1309   if (!fp)
1310     return false;
1311   
1312   // read file
1313   Array<BYTE> buf(static_cast<size_t>(sbuf.st_size) + 1);
1314   if (fread(buf.get(), static_cast<size_t>(sbuf.st_size), 1, fp) != 1)
1315   {
1316     fclose(fp);
1317     return false;
1318   }
1319   buf.get()[sbuf.st_size] = 0;                  // mbstowcs() requires null
1320                                                 // terminated string
1321
1322 #ifdef _UNICODE
1323   //
1324   if (buf.get()[0] == 0xffU && buf.get()[1] == 0xfeU &&
1325       sbuf.st_size % 2 == 0)
1326     // UTF-16 Little Endien
1327   {
1328     size_t size = static_cast<size_t>(sbuf.st_size) / 2;
1329     o_data->resize(size);
1330     BYTE *p = buf.get();
1331     for (size_t i = 0; i < size; ++ i)
1332     {
1333       wchar_t c = static_cast<wchar_t>(*p ++);
1334       c |= static_cast<wchar_t>(*p ++) << 8;
1335       (*o_data)[i] = c;
1336     }
1337     fclose(fp);
1338     return true;
1339   }
1340   
1341   //
1342   if (buf.get()[0] == 0xfeU && buf.get()[1] == 0xffU &&
1343       sbuf.st_size % 2 == 0)
1344     // UTF-16 Big Endien
1345   {
1346     size_t size = static_cast<size_t>(sbuf.st_size) / 2;
1347     o_data->resize(size);
1348     BYTE *p = buf.get();
1349     for (size_t i = 0; i < size; ++ i)
1350     {
1351       wchar_t c = static_cast<wchar_t>(*p ++) << 8;
1352       c |= static_cast<wchar_t>(*p ++);
1353       (*o_data)[i] = c;
1354     }
1355     fclose(fp);
1356     return true;
1357   }
1358
1359   // try multibyte charset 
1360   size_t wsize = mbstowcs(NULL, reinterpret_cast<char *>(buf.get()), 0);
1361   if (wsize != size_t(-1))
1362   {
1363     Array<wchar_t> wbuf(wsize);
1364     mbstowcs(wbuf.get(), reinterpret_cast<char *>(buf.get()), wsize);
1365     o_data->assign(wbuf.get(), wbuf.get() + wsize);
1366     fclose(fp);
1367     return true;
1368   }
1369   
1370   // try UTF-8
1371   {
1372     Array<wchar_t> wbuf(static_cast<size_t>(sbuf.st_size));
1373     BYTE *f = buf.get();
1374     BYTE *end = buf.get() + sbuf.st_size;
1375     wchar_t *d = wbuf.get();
1376     enum { STATE_1, STATE_2of2, STATE_2of3, STATE_3of3 } state = STATE_1;
1377     
1378     while (f != end)
1379     {
1380       switch (state)
1381       {
1382         case STATE_1:
1383           if (!(*f & 0x80))                     // 0xxxxxxx: 00-7F
1384             *d++ = static_cast<wchar_t>(*f++);
1385           else if ((*f & 0xe0) == 0xc0)         // 110xxxxx 10xxxxxx: 0080-07FF
1386           {
1387             *d = ((static_cast<wchar_t>(*f++) & 0x1f) << 6);
1388             state = STATE_2of2;
1389           }
1390           else if ((*f & 0xf0) == 0xe0)         // 1110xxxx 10xxxxxx 10xxxxxx:
1391                                                 // 0800 - FFFF
1392           {
1393             *d = ((static_cast<wchar_t>(*f++) & 0x0f) << 12);
1394             state = STATE_2of3;
1395           }
1396           else
1397             goto not_UTF_8;
1398           break;
1399           
1400         case STATE_2of2:
1401         case STATE_3of3:
1402           if ((*f & 0xc0) != 0x80)
1403             goto not_UTF_8;
1404           *d++ |= (static_cast<wchar_t>(*f++) & 0x3f);
1405           state = STATE_1;
1406           break;
1407
1408         case STATE_2of3:
1409           if ((*f & 0xc0) != 0x80)
1410             goto not_UTF_8;
1411           *d |= ((static_cast<wchar_t>(*f++) & 0x3f) << 6);
1412           state = STATE_3of3;
1413           break;
1414       }
1415     }
1416     o_data->assign(wbuf.get(), d);
1417     fclose(fp);
1418     return true;
1419     
1420     not_UTF_8: ;
1421   }
1422 #endif // _UNICODE
1423
1424   // assume ascii
1425   o_data->resize(static_cast<size_t>(sbuf.st_size));
1426   for (off_t i = 0; i < sbuf.st_size; ++ i)
1427     (*o_data)[i] = buf.get()[i];
1428   fclose(fp);
1429   return true;
1430 }
1431
1432
1433 // load (called from load(Setting *, const tstringi &) only)
1434 void SettingLoader::load(const tstringi &i_filename)
1435 {
1436   m_currentFilename = i_filename;
1437   
1438   tstring data;
1439   if (!readFile(&data, m_currentFilename))
1440   {
1441     Acquire a(m_soLog);
1442     *m_log << m_currentFilename << _T(" : error: file not found") << std::endl;
1443 #if 1
1444     *m_log << data << std::endl;
1445 #endif
1446     m_isThereAnyError = true;
1447     return;
1448   }
1449   
1450   // prefix
1451   if (m_prefixesRefCcount == 0)
1452   {
1453     static const _TCHAR *prefixes[] =
1454     {
1455       _T("="), _T("=>"), _T("&&"), _T("||"), _T(":"), _T("$"), _T("&"),
1456       _T("-="), _T("+="), _T("!!!"), _T("!!"), _T("!"), 
1457       _T("E0-"), _T("E1-"),                     // <SCAN_CODE_EXTENTION>
1458       _T("S-"), _T("A-"), _T("M-"), _T("C-"),   // <BASIC_MODIFIER>
1459       _T("W-"), _T("*"), _T("~"),
1460       _T("U-"), _T("D-"),                       // <KEYSEQ_MODIFIER>
1461       _T("R-"), _T("IL-"), _T("IC-"), _T("I-"), // <ASSIGN_MODIFIER>
1462       _T("NL-"), _T("CL-"), _T("SL-"), _T("KL-"),
1463       _T("MAX-"), _T("MIN-"), _T("MMAX-"), _T("MMIN-"),
1464       _T("T-"), _T("TS-"),
1465       _T("M0-"), _T("M1-"), _T("M2-"), _T("M3-"), _T("M4-"),
1466       _T("M5-"), _T("M6-"), _T("M7-"), _T("M8-"), _T("M9-"), 
1467       _T("L0-"), _T("L1-"), _T("L2-"), _T("L3-"), _T("L4-"),
1468       _T("L5-"), _T("L6-"), _T("L7-"), _T("L8-"), _T("L9-"), 
1469     };
1470     m_prefixes = new std::vector<tstringi>;
1471     for (size_t i = 0; i < NUMBER_OF(prefixes); ++ i)
1472       m_prefixes->push_back(prefixes[i]);
1473     std::sort(m_prefixes->begin(), m_prefixes->end(), prefixSortPred);
1474   }
1475   m_prefixesRefCcount ++;
1476
1477   // create parser
1478   Parser parser(data.c_str(), data.size());
1479   parser.setPrefixes(m_prefixes);
1480     
1481   while (true)
1482   {
1483     try
1484     {
1485       if (!parser.getLine(&m_tokens))
1486         break;
1487       m_ti = m_tokens.begin();
1488     }
1489     catch (ErrorMessage &e)
1490     {
1491       if (m_log && m_soLog)
1492       {
1493         Acquire a(m_soLog);
1494         *m_log << m_currentFilename << _T("(") << parser.getLineNumber()
1495                << _T(") : error: ") << e << std::endl;
1496       }
1497       m_isThereAnyError = true;
1498       continue;
1499     }
1500       
1501     try
1502     {
1503       load_LINE();
1504       if (!isEOL())
1505         throw WarningMessage() << _T("back garbage is ignored.");
1506     }
1507     catch (WarningMessage &w)
1508     {
1509       if (m_log && m_soLog)
1510       {
1511         Acquire a(m_soLog);
1512         *m_log << i_filename << _T("(") << parser.getLineNumber()
1513                << _T(") : warning: ") << w << std::endl;
1514       }
1515     }
1516     catch (ErrorMessage &e)
1517     {
1518       if (m_log && m_soLog)
1519       {
1520         Acquire a(m_soLog);
1521         *m_log << i_filename << _T("(") << parser.getLineNumber()
1522                << _T(") : error: ") << e << std::endl;
1523       }
1524       m_isThereAnyError = true;
1525     }
1526   }
1527     
1528   // m_prefixes
1529   -- m_prefixesRefCcount;
1530   if (m_prefixesRefCcount == 0)
1531     delete m_prefixes;
1532
1533   if (0 < m_canReadStack.size())
1534   {
1535     Acquire a(m_soLog);
1536     *m_log << m_currentFilename << _T("(") << parser.getLineNumber()
1537            << _T(") : error: unbalanced `if'.  ")
1538            << _T("you forget `endif', didn'i_token you?")
1539            << std::endl;
1540     m_isThereAnyError = true;
1541   }
1542 }
1543
1544
1545 // is the filename readable ?
1546 bool SettingLoader::isReadable(const tstringi &i_filename,
1547                                int i_debugLevel) const 
1548 {
1549   if (i_filename.empty())
1550     return false;
1551 #ifdef UNICODE
1552   tifstream ist(to_string(i_filename).c_str());
1553 #else
1554   tifstream ist(i_filename.c_str());
1555 #endif
1556   if (ist.good())
1557   {
1558     if (m_log && m_soLog)
1559     {
1560                 Acquire a(m_soLog, 0);
1561       *m_log << _T("  loading: ") << i_filename << std::endl;
1562     }
1563     return true;
1564   }
1565   else
1566   {
1567     if (m_log && m_soLog)
1568     {
1569       Acquire a(m_soLog, i_debugLevel);
1570       *m_log << _T("not found: ") << i_filename << std::endl;
1571     }
1572     return false;
1573   }
1574 }
1575
1576 #if 0
1577 // get filename from registry
1578 bool SettingLoader::getFilenameFromRegistry(tstringi *o_path) const
1579 {
1580   // get from registry
1581   Registry reg(MAYU_REGISTRY_ROOT);
1582   int index;
1583   reg.read(_T(".mayuIndex"), &index, 0);
1584   char buf[100];
1585   snprintf(buf, NUMBER_OF(buf), _T(".mayu%d"), index);
1586   if (!reg.read(buf, o_path))
1587     return false;
1588
1589   // parse registry entry
1590   Regexp getFilename(_T("^[^;]*;([^;]*);(.*)$"));
1591   if (!getFilename.doesMatch(*o_path))
1592     return false;
1593   
1594   tstringi path = getFilename[1];
1595   tstringi options = getFilename[2];
1596   
1597   if (!(0 < path.size() && isReadable(path)))
1598     return false;
1599   *o_path = path;
1600   
1601   // set symbols
1602   Regexp symbol(_T("-D([^;]*)"));
1603   while (symbol.doesMatch(options))
1604   {
1605     m_setting->symbols.insert(symbol[1]);
1606     options = options.substr(symbol.subBegin(1));
1607   }
1608   
1609   return true;
1610 }
1611 #endif
1612
1613
1614 // get filename
1615 bool SettingLoader::getFilename(const tstringi &i_name, tstringi *o_path,
1616                                 int i_debugLevel) const
1617 {
1618   // the default filename is ".mayu"
1619   const tstringi &name = i_name.empty() ? tstringi(_T(".mayu")) : i_name;
1620   
1621   bool isFirstTime = true;
1622
1623   while (true)
1624   {
1625     // find file from registry
1626     if (i_name.empty())                         // called not from 'include'
1627     {
1628       Setting::Symbols symbols;
1629       if (getFilenameFromRegistry(NULL, o_path, &symbols))
1630       {
1631         if (o_path->empty())
1632           // find file from home directory
1633         {
1634           HomeDirectories pathes;
1635           getHomeDirectories(&pathes);
1636           for (HomeDirectories::iterator
1637                  i = pathes.begin(); i != pathes.end(); ++ i)
1638           {
1639             *o_path = *i + _T("\\") + name;
1640             if (isReadable(*o_path, i_debugLevel))
1641               goto add_symbols;
1642           }
1643           return false;
1644         }
1645         else
1646         {
1647           if (!isReadable(*o_path, i_debugLevel))
1648             return false;
1649         }
1650         add_symbols:
1651         for (Setting::Symbols::iterator
1652                i = symbols.begin(); i != symbols.end(); ++ i)
1653           m_setting->m_symbols.insert(*i);
1654         return true;
1655       }
1656     }
1657     
1658     if (!isFirstTime)
1659       return false;
1660     
1661     // find file from home directory
1662     HomeDirectories pathes;
1663     getHomeDirectories(&pathes);
1664     for (HomeDirectories::iterator i = pathes.begin(); i != pathes.end(); ++ i)
1665     {
1666       *o_path = *i + _T("\\") + name;
1667       if (isReadable(*o_path, i_debugLevel))
1668         return true;
1669     }
1670     
1671     if (!i_name.empty())
1672       return false;                             // called by 'include'
1673     
1674     if (!DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_setting),
1675                    NULL, dlgSetting_dlgProc))
1676       return false;
1677   }
1678 }
1679
1680
1681 // constructor
1682 SettingLoader::SettingLoader(SyncObject *i_soLog, tostream *i_log)
1683   : m_setting(NULL),
1684     m_isThereAnyError(false),
1685     m_soLog(i_soLog),
1686     m_log(i_log),
1687     m_currentKeymap(NULL)
1688 {
1689   m_defaultKeySeqModifier =
1690     m_defaultAssignModifier.release(Modifier::Type_ImeComp);
1691 }
1692
1693
1694 /* load m_setting
1695    If called by "include", 'filename' describes filename.
1696    Otherwise the 'filename' is empty.
1697  */
1698 bool SettingLoader::load(Setting *i_setting, const tstringi &i_filename)
1699 {
1700   m_setting = i_setting;
1701   m_isThereAnyError = false;
1702     
1703   tstringi path;
1704   if (!getFilename(i_filename, &path))
1705   {
1706     if (i_filename.empty())
1707     {
1708       Acquire a(m_soLog);
1709       getFilename(i_filename, &path, 0);        // show filenames
1710       return false;
1711     }
1712     else
1713       throw ErrorMessage() << _T("`") << i_filename
1714                            << _T("': no such file or other error.");
1715   }
1716
1717   // create global keymap's default keySeq
1718   ActionFunction af(createFunctionData(_T("OtherWindowClass")));
1719   KeySeq *globalDefault = m_setting->m_keySeqs.add(KeySeq(_T("")).add(af));
1720   
1721   // add default keymap
1722   m_currentKeymap = m_setting->m_keymaps.add(
1723     Keymap(Keymap::Type_windowOr, _T("Global"), _T(""), _T(""),
1724            globalDefault, NULL));
1725
1726   /*
1727   // add keyboard layout name
1728   if (filename.empty())
1729   {
1730     char keyboardLayoutName[KL_NAMELENGTH];
1731     if (GetKeyboardLayoutName(keyboardLayoutName))
1732     {
1733       tstringi kl = tstringi(_T("KeyboardLayout/")) + keyboardLayoutName;
1734       m_setting->symbols.insert(kl);
1735       Acquire a(m_soLog);
1736       *m_log << _T("KeyboardLayout: ") << kl << std::endl;
1737     }
1738   }
1739   */
1740   
1741   // load
1742   load(path);
1743
1744   // finalize
1745   if (i_filename.empty())
1746     m_setting->m_keymaps.adjustModifier(m_setting->m_keyboard);
1747   
1748   return !m_isThereAnyError;
1749 }
1750
1751
1752 std::vector<tstringi> *SettingLoader::m_prefixes; // m_prefixes terminal symbol
1753 size_t SettingLoader::m_prefixesRefCcount;      /* reference count of
1754                                                    m_prefixes */