OSDN Git Service

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