16aae9308c1f92060b2521afc2ef2f895cbde2d0
[reactos.git] / reactos / base / applications / network / telnet / src / tmapldr.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998-2000 Paul Brannan
4 //Copyright (C) 1998 I.Ioannou
5 //Copyright (C) 1997 Brad Johnson
6 //
7 //This program is free software; you can redistribute it and/or
8 //modify it under the terms of the GNU General Public License
9 //as published by the Free Software Foundation; either version 2
10 //of the License, or (at your option) any later version.
11 //
12 //This program is distributed in the hope that it will be useful,
13 //but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 //GNU General Public License for more details.
16 //
17 //You should have received a copy of the GNU General Public License
18 //along with this program; if not, write to the Free Software
19 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 //I.Ioannou
22 //roryt@hol.gr
23 //
24 ///////////////////////////////////////////////////////////////////////////
25
26 /////////////////////////////////////////////////////////
27 // Class TMapLoader - Key/Character Mappings //
28 // - Loads from telnet.cfg //
29 // originally part of KeyTrans.cpp //
30 /////////////////////////////////////////////////////////
31
32 #ifdef __BORLANDC__
33 #include <fstream.h>
34 #else
35 #include <string>
36 #include <fstream>
37 #endif
38
39 #include "tmapldr.h"
40 #include "tnerror.h"
41 #include "tnconfig.h"
42
43 // It's probably a good idea to turn off the "identifier was truncated" warning
44 // in MSVC (Paul Brannan 5/25/98)
45 #ifdef _MSC_VER
46 #pragma warning(disable: 4786)
47 #endif
48
49 // AVS
50 // skip inline comments, empty lines
51 static char * getline(istream& i, char* buf, int size){
52
53 int len = 0;
54
55 while (1) {
56 memset(buf,0,size);
57 if (i.eof()) break;
58 i.getline(buf,size,'\n');
59
60 while (buf[len]) {
61 if ( /*(buf[len]>=0) &&*/ buf[len]< ' ' ) buf[len] = ' ';
62 len++;
63 };
64 len = 0;
65
66 // not so fast, but work ;)
67 while ( buf[len] ) {
68 if ( (buf[len] == ' ') && (buf[len+1] == ' ')) {
69 memmove(buf+len, buf+len+1, strlen(buf+len));
70 } else len++;
71 };
72
73 if (buf[0] == ' ') memmove(buf, buf+1, size-1);
74
75 // empty or comment
76 if ((buf[0]==0)||(buf[0]==';')) continue;
77
78 len = 0; // look for comment like this one
79 while (buf[len])
80 if ((buf[len] == '/') && (buf[len+1] == '/')) buf[len] = 0;
81 else len++;
82
83 if (len && (buf[len-1] == ' ')) {
84 len--;
85 buf[len]=0;
86 };
87 // in case for comment like this one (in line just a comment)
88 if (buf[0]==0) continue;
89
90 break;
91 };
92 return (buf);
93 };
94
95 //AVS
96 // use string as FIFO queue for lines
97 static int getline(string&str, char* buf, size_t sz) {
98
99 if ( !str.length() ) return 0;
100 const char * p = strchr(str.c_str(),'\n');
101 unsigned int len; // Changed to unsigned (Paul Brannan 6/23/98)
102 if ( p==NULL )
103 len = str.length();
104 else
105 len = p - str.c_str();
106
107 len = len<sz?len:sz-1;
108
109 strncpy(buf,str.c_str(), len);
110 buf[len]=0;
111 // DJGPP also uses erase rather than remove (Paul Brannan 6/23/98)
112 #ifndef __BORLANDC__
113 str.erase(0, len + 1);
114 #else
115 str.remove(0,len+1);
116 #endif
117 return 1;
118 };
119
120 //AVS
121 // parse \nnn and \Xhh
122 static int getbyte(const char*str) {
123 unsigned char retval = 0;
124 int base = 10;
125 int readed = 0;
126
127 if ( (*str == 'x') || (*str == 'X') ) {
128 base = 16;
129 readed++;
130 };
131
132 while (readed != 3 && str[readed]) {
133 unsigned char ch = toupper(str[readed]);
134 if ( isdigit(ch) ) {
135 retval = retval*base + (ch -'0');
136 } else if (base == 16 && ch >= 'A' && ch <= 'F') {
137 retval = retval*base + (ch-'A'+10);
138 } else {
139 return -1;
140 };
141 readed++;
142 };
143 // Ioannou: If we discard the 0x00 we can't undefine a key !!!
144 // if ( retval == 0 ) {
145 // return -1;
146 // };
147 return retval;
148 };
149
150 //AVS
151 // a little optimization
152 DWORD Fix_ControlKeyState(char * Next_Token) {
153 if (stricmp(Next_Token, "RIGHT_ALT" ) == 0) return RIGHT_ALT_PRESSED;
154 if (stricmp(Next_Token, "LEFT_ALT" ) == 0) return LEFT_ALT_PRESSED;
155 if (stricmp(Next_Token, "RIGHT_CTRL") == 0) return RIGHT_CTRL_PRESSED;
156 if (stricmp(Next_Token, "LEFT_CTRL" ) == 0) return LEFT_CTRL_PRESSED;
157 if (stricmp(Next_Token, "SHIFT" ) == 0) return SHIFT_PRESSED;
158 if (stricmp(Next_Token, "NUMLOCK" ) == 0) return NUMLOCK_ON;
159 if (stricmp(Next_Token, "SCROLLLOCK") == 0) return SCROLLLOCK_ON;
160 if (stricmp(Next_Token, "CAPSLOCK" ) == 0) return CAPSLOCK_ON;
161 if (stricmp(Next_Token, "ENHANCED" ) == 0) return ENHANCED_KEY;
162
163 // Paul Brannan 5/27/98
164 if (stricmp(Next_Token, "APP_KEY" ) == 0) return APP_KEY;
165 // Paul Brannan 6/28/98
166 if (stricmp(Next_Token, "APP2_KEY" ) == 0) return APP2_KEY;
167 // Paul Brannan 8/28/98
168 if (stricmp(Next_Token, "APP3_KEY" ) == 0) return APP3_KEY;
169 // Paul Brannan 12/9/98
170 if (stricmp(Next_Token, "APP4_KEY" ) == 0) return APP4_KEY;
171
172 return 0;
173 }
174
175
176 // AVS
177 // rewrited to suppert \xhh notation, a little optimized
178 char* Fix_Tok(char * tok) {
179 static char s[256];
180 int i,j,n;
181
182 // setmem is nonstandard; memset is standard (Paul Brannan 5/25/98)
183 memset(s, 0, 256);
184 // setmem(s, 256, 0);
185 i = j = n = 0;
186 if ( tok != NULL ) {
187 for ( ; tok[i] != 0; ) {
188 switch ( tok[i] ) {
189 case '\\' :
190 switch ( tok[i+1] ) {
191 case '\\':
192 s[j++] = '\\';
193 i += 2;
194 break;
195 default:
196 n = getbyte(tok+i+1);
197 if ( n < 0 )
198 s[j++] = tok[i++];
199 else {
200 s[j++]=n;
201 i += 4;
202 } ;
203 break;
204 };
205 break;
206 case '^' :
207 if ( tok[i+1] >= '@' ) {
208 s[j++] = tok[i+1] - '@';
209 i += 2;
210 break;
211 }
212 default :
213 s[j++] = tok[i++];
214 }
215 }
216 }
217 return s;
218 };
219
220 // AVS
221 // perform 'normalization' for lines like [some text], and some checks
222 // maybe it will be done faster - but no time for it
223 int normalizeSplitter(string& buf) {
224 if ( buf.length() <= 2 ) return 0;
225 if ( buf[0] == '[' && buf[buf.length()-1] == ']' ) {
226 while ( buf[1] == ' ' )
227 // DJGPP also uses erase rather than remove (Paul Brannan 6/23/98)
228 #ifndef __BORLANDC__
229 buf.erase(1, 1);
230 #else
231 buf.remove(1,1);
232 #endif
233 while ( buf[buf.length()-2] == ' ' )
234 // Paul Brannan 6/23/98
235 #ifndef __BORLANDC__
236 buf.erase(buf.length()-2,1);
237 #else
238 buf.remove(buf.length()-2,1);
239 #endif
240 return 1;
241 }
242 return 0;
243 };
244
245 // AVS
246 // looking for part in string array, see Load(..) for more info
247 int TMapLoader::LookForPart(stringArray& sa, const char* partType, const char* partName) {
248 if ( !sa.IsEmpty() ) {
249 string cmpbuf("[");
250 cmpbuf += partType;
251 cmpbuf += " ";
252 cmpbuf += partName;
253 cmpbuf += "]";
254 normalizeSplitter(cmpbuf); // if no parttype, [global] for example
255 int max = sa.GetItemsInContainer();
256 for ( int i = 0; i<max; i++ )
257 // I found some strange behavior if strnicmp was used here
258 if (strnicmp(cmpbuf.c_str(),sa[i].c_str(),cmpbuf.length()) == 0)
259 return i;
260 };
261 return INT_MAX;
262 };
263
264 // AVS
265 // load globals to 'globals'
266 // in buf must be a [global] part of input file
267 int TMapLoader::LoadGlobal(string& buf) {
268
269 char wbuf[128];
270 while ( buf.length() ) {
271 wbuf[0]=0;
272 if (!getline(buf,wbuf,sizeof(wbuf))) break;
273 if ( wbuf[0]==0 ) break;
274 char* Name = strtok(wbuf, TOKEN_DELIMITERS);
275 if ( stricmp(Name, "[global]")==0 ) continue;
276
277 char* Value = strtok(NULL, TOKEN_DELIMITERS);
278 if ( Value == NULL ) {
279 // cerr << "[global] -> no value for " << Name << endl;
280 printm(0, FALSE, MSG_KEYNOVAL, Name);
281 continue;
282 };
283 int val = atoi(Value);
284 if ( val > 0 && val <= 0xff ) {
285 if ( !KeyTrans.AddGlobalDef(val, Name)) return 0;
286 }
287 else {
288 // cerr << "[global] -> bad value for " << Name << endl;
289 printm(0, FALSE, MSG_KEYBADVAL, Name);
290 continue;
291 };
292 };
293 return 1;
294 };
295
296 // AVS
297 // perform parsing of strings like 'VK_CODE shifts text'
298 // returns text on success
299 char* TMapLoader::ParseKeyDef(const char* buf, WORD& vk_code, DWORD& control) {
300 char wbuf[256];
301 strcpy(wbuf,buf);
302 char* ptr = strtok(wbuf, TOKEN_DELIMITERS);
303 if ( ptr == NULL ) return NULL;
304
305 int i = KeyTrans.LookOnGlobal(ptr);
306 if ( i == INT_MAX ) return NULL;
307
308 vk_code = KeyTrans.GetGlobalCode(i);
309
310 control = 0;
311 DWORD st;
312 while (1) {
313 ptr = strtok(NULL, TOKEN_DELIMITERS);
314 if ((ptr == NULL) || ((st = Fix_ControlKeyState(ptr)) == 0)) break;
315 control |= st;
316 };
317
318 if ( ptr == NULL ) return NULL;
319
320 return Fix_Tok(ptr);
321 };
322
323 // AVS
324 // load keymap to current map
325 // be aware - buf must passed by value, its destroyed
326 int TMapLoader::LoadKeyMap(string buf) {
327
328 char wbuf[128];
329 WORD vk_code;
330 DWORD control;
331 int i;
332
333 // Paul Brannan Feb. 22, 1999
334 strcpy(wbuf, "VK_");
335 wbuf[4] = 0;
336 wbuf[3] = ini.get_escape_key();
337 i = KeyTrans.LookOnGlobal(wbuf);
338 if (i != INT_MAX) {
339 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), RIGHT_ALT_PRESSED, TN_ESCAPE);
340 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), LEFT_ALT_PRESSED, TN_ESCAPE);
341 }
342 wbuf[3] = ini.get_scrollback_key();
343 i = KeyTrans.LookOnGlobal(wbuf);
344 if (i != INT_MAX) {
345 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), RIGHT_ALT_PRESSED, TN_SCROLLBACK);
346 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), LEFT_ALT_PRESSED, TN_SCROLLBACK);
347 }
348 wbuf[3] = ini.get_dial_key();
349 i = KeyTrans.LookOnGlobal(wbuf);
350 if (i != INT_MAX) {
351 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), RIGHT_ALT_PRESSED, TN_DIAL);
352 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), LEFT_ALT_PRESSED, TN_DIAL);
353 }
354 KeyTrans.AddKeyDef(VK_INSERT, SHIFT_PRESSED, TN_PASTE);
355
356 while ( buf.length() ) {
357 wbuf[0] = 0;
358 if (!getline(buf,wbuf,sizeof(wbuf))) break;
359 if ( wbuf[0]==0 ) break;
360 if ( strnicmp(wbuf,"[keymap",7)==0 ) continue;
361
362 char * keydef = ParseKeyDef(wbuf,vk_code,control);
363
364 if ( keydef != NULL ) {
365
366 // Check to see if keydef is a "special" code (Paul Brannan 3/29/00)
367 if(!strnicmp(keydef, "\\tn_escape", strlen("\\tn_escape"))) {
368 if(!KeyTrans.AddKeyDef(vk_code, control, TN_ESCAPE)) return 0;
369 } else if(!strnicmp(keydef, "\\tn_scrollback", strlen("\\tn_scrollback"))) {
370 if(!KeyTrans.AddKeyDef(vk_code, control, TN_SCROLLBACK)) return 0;
371 } else if(!strnicmp(keydef, "\\tn_dial", strlen("\\tn_dial"))) {
372 if(!KeyTrans.AddKeyDef(vk_code, control, TN_DIAL)) return 0;
373 } else if(!strnicmp(keydef, "\\tn_paste", strlen("\\tn_paste"))) {
374 if(!KeyTrans.AddKeyDef(vk_code, control, TN_PASTE)) return 0;
375 } else if(!strnicmp(keydef, "\\tn_null", strlen("\\tn_null"))) {
376 if(!KeyTrans.AddKeyDef(vk_code, control, TN_NULL)) return 0;
377 } else if(!strnicmp(keydef, "\\tn_cr", strlen("\\tn_cr"))) {
378 if(!KeyTrans.AddKeyDef(vk_code, control, TN_CR)) return 0;
379 } else if(!strnicmp(keydef, "\\tn_crlf", strlen("\\tn_crlf"))) {
380 if(!KeyTrans.AddKeyDef(vk_code, control, TN_CRLF)) return 0;
381 } else
382 if(!KeyTrans.AddKeyDef(vk_code,control,keydef)) return 0;
383 // else DeleteKeyDef() ???? - I'm not sure...
384 }
385 };
386
387 return 1;
388 };
389
390 // AVS
391 // load [charmap ...] part to xlat
392 int TMapLoader::LoadCharMap(string buf) {
393 char wbuf[128];
394 char charmapname[128];
395 charmapname[0] = 0;
396
397 // xlat.init(); now it done by KeyTranslator::Load()
398
399 while ( buf.length() ) {
400 wbuf[0]=0;
401 if (!getline(buf,wbuf,sizeof(wbuf))) break;
402 if ( wbuf[0]==0 ) break;
403 if ( strnicmp(wbuf,"[charmap",8)==0 ) {
404 strcpy(charmapname,wbuf);
405 continue;
406 };
407 char * host = strtok(wbuf, " ");
408 char * console = strtok(NULL, " ");
409
410 int bHost;
411 int bConsole;
412
413 if ( host == NULL || console == NULL ) {
414 // cerr << charmapname << " -> Bad structure" << endl;
415 printm(0, FALSE, MSG_KEYBADSTRUCT, charmapname);
416 return 0;
417 };
418 if ( strlen(host) > 1 && host[0] == '\\' )
419 bHost = getbyte(host+1);
420 else
421 bHost = (unsigned char)host[0];
422
423 if ( strlen(console) > 1 && console[0] == '\\' )
424 bConsole = getbyte(console+1);
425 else
426 bConsole = (unsigned char)console[0];
427
428 if ( bHost <= 0 || bConsole <= 0 ) {
429 // cerr << charmapname << " -> Bad chars? "
430 // << host << " -> " << console << endl;
431 printm(0, FALSE, MSG_KEYBADCHARS, charmapname, host, console);
432 return 0;
433 };
434 // xlat.table[bHost] = bConsole;
435 Charmap.modmap(bHost, 'B', bConsole);
436 };
437 return (Charmap.enabled = 1);
438 return 1;
439 };
440
441 // AVS
442 // ignore long comment [comment] ... [end comment]
443 // recursive!
444 int getLongComment(istream& is, char* wbuf, size_t sz) {
445
446 int bufLen;
447 while ( is ) {
448 wbuf[0] = 0;
449 getline(is, wbuf, sz);
450 if ( wbuf[0]==0 ) return 1;
451 bufLen = strlen(wbuf);
452 if ( wbuf[0] == '[' && wbuf[bufLen-1] == ']' ) {
453 string temps(wbuf);
454
455 if (!normalizeSplitter(temps)) {
456 // cerr << "Unexpected line '" << temps << "'\n";
457 printm(0, FALSE, MSG_KEYUNEXPLINE, temps.c_str());
458 return 0;
459 };
460 if ( stricmp(temps.c_str(),"[comment]") == 0 ) {
461 // do recursive call
462 if ( !getLongComment(is, wbuf, sz) ) return 0;
463 continue;
464 };
465 if ( stricmp(temps.c_str(),"[end comment]") == 0 ) return 1;
466 };
467 };
468 // we get a warning if we don't put a return here (Paul Brannan 5/25/98)
469 return 0;
470 };
471
472 // AVS
473 // completelly rewrited to support new conceptions
474 int TMapLoader::Load(const char * filename, const char * szActiveEmul) {
475 char buf[256];
476 int bufLen;
477
478 ifstream inpfile(filename);
479 KeyTrans.DeleteAllDefs();
480 Charmap.init();
481
482 // it is an array for store [...] ... [end ...] parts from file
483 stringArray SA(0,0,sizeof(string));
484 int AllOk = 0;
485
486 while ( inpfile ) {
487
488 getline(inpfile, buf, 255);
489 bufLen = strlen(buf);
490 if ( !bufLen ) continue;
491
492 if ( buf[0] == '[' && buf[bufLen-1] == ']' ) {
493 // is a part splitter [...]
494 string temps(buf);
495
496 if (!normalizeSplitter(temps)) {
497 printm(0, FALSE, MSG_KEYUNEXPLINE, temps.c_str());
498 AllOk = 0;
499 break;
500 };
501 // if a comment
502 if ( stricmp(temps.c_str(),"[comment]") == 0 ) {
503 #ifdef KEYDEBUG
504 printit(temps.c_str());
505 #endif
506 if ( !getLongComment(inpfile, buf, sizeof(buf)) ) {
507 printm(0, FALSE, MSG_KEYUNEXPEOF);
508 break;
509 };
510 #ifdef KEYDEBUG
511 printit("\r \r");
512 #endif
513 continue;
514 };
515
516
517 string back = temps;
518 // prepare line for make it as [end ...]
519 // and check it
520 if ( strnicmp(back.c_str(), "[global]", 8) == 0 ) {} // do nothing
521 else if ( strnicmp(back.c_str(), "[keymap", 7) == 0 ) {
522 // DJGPP also uses erase rather than remove (Paul Brannan 6/23/98)
523 #ifndef __BORLANDC__
524 back.erase(7);
525 #else
526 back.remove(7);
527 #endif
528 back += "]";
529 }
530 else if ( strnicmp(back.c_str(), "[charmap", 8) == 0 ) {
531 // Paul Brannan 6/23/98
532 #ifndef __BORLANDC__
533 back.erase(8);
534 #else
535 back.remove(8);
536 #endif
537 back += "]";
538 }
539 else if ( strnicmp(back.c_str(), "[config", 7) == 0 ) {
540 // Paul Brannan 6/23/98
541 #ifndef __BORLANDC__
542 back.erase(7);
543 #else
544 back.remove(7);
545 #endif
546 back += "]";
547 }
548 else {
549 // cerr << "Unexpected token " << back << endl;
550 printm(0, FALSE, MSG_KEYUNEXPTOK, back.c_str());
551 break;
552 };
553
554 back.insert(1,"END "); // now it looks like [END ...]
555 #ifdef KEYDEBUG
556 printit(temps.c_str());
557 #endif
558
559 int ok = 0;
560 // fetch it to temps
561 while ( 1 ) {
562 getline(inpfile, buf, sizeof(buf));
563 bufLen = strlen(buf);
564 if ( !bufLen ) break;
565 if ( buf[0] == '[' && buf[bufLen-1] == ']' ) {
566 string t(buf);
567 if ( !normalizeSplitter(t) ) break;
568
569 if ( stricmp(t.c_str(),back.c_str()) == 0 ) {
570 ok = 1;
571 break;
572 };
573
574 // AVS 31.12.97 fix [comment] block inside another block
575 if ( stricmp(t.c_str(),"[comment]") == 0 &&
576 getLongComment(inpfile, buf, sizeof(buf)) ) continue;
577
578 break;
579 };
580 temps += "\n";
581 temps += buf;
582 };
583 if ( !ok ) {
584 // cerr << "Unexpected end of file or token" << endl;
585 printm(0, FALSE, MSG_KEYUNEXP);
586 AllOk = 0;
587 break;
588 };
589 #ifdef KEYDEBUG
590 printit("\r \r");
591 #endif
592 AllOk = SA.Add(temps);;
593 if ( !AllOk ) break;
594 } else {
595 // cerr << "Unexpected line '" << buf << "'\n";
596 printm(0, FALSE, MSG_KEYUNEXPLINE, buf);
597 AllOk = 0;
598 break;
599 };
600 };
601
602 inpfile.close();
603
604 if ( !AllOk ) return 0;
605
606 // now all file are in SA, comments are stripped
607
608 int i = LookForPart(SA, "global", "");
609 if ( i == INT_MAX ) {
610 // cerr << "No [GLOBAL] definition!" << endl;
611 printm(0, FALSE, MSG_KEYNOGLOBAL);
612 return 0;
613 };
614 if ( !LoadGlobal(SA[i]) ) {
615 return 0;
616 };
617
618 // look for need configuration
619 i = LookForPart(SA, "config", szActiveEmul);
620 if ( i == INT_MAX ) {
621 // cerr << "No [CONFIG " << szActiveEmul << "]\n";
622 printm(0, FALSE, MSG_KEYNOCONFIG, szActiveEmul);
623 return 0;
624 };
625 // cerr << "use configuration: " << szActiveEmul << endl;
626 printm(0, FALSE, MSG_KEYUSECONFIG, szActiveEmul);
627 BOOL hadKeys = FALSE;
628
629 string config = SA[i];
630 // parse it
631 while ( config.length() ) {
632 buf[0] = 0;
633 getline(config,buf,sizeof(buf));
634 bufLen = strlen(buf);
635 if ( !bufLen || (buf[0] == '[' && buf[bufLen-1] == ']') ) continue;
636 if ( strnicmp(buf,"keymap",6) == 0 ) {
637 string orig(buf);
638 printit("\t"); printit(buf); printit("\n");
639 char * mapdef = strtok(buf,":");
640 char * switchKey = strtok(NULL,"\n");
641
642 if ( !KeyTrans.mapArray.IsEmpty() && switchKey == NULL ) {
643 // cerr << "no switch Key for '" << mapdef
644 // << "'" << endl;
645 printm(0, FALSE, MSG_KEYNOSWKEY, mapdef);
646 break;
647 };
648 if ( KeyTrans.mapArray.IsEmpty() ) {
649 if ( switchKey != NULL ) { // create default keymap
650 // cerr << "You cannot define switch key for default keymap -> ignored"
651 // << endl;
652 printm(0, FALSE, MSG_KEYCANNOTDEF);
653 };
654 TKeyDef empty;
655 KeyTrans.mapArray.Add(KeyMap(string(mapdef)));
656 KeyTrans.switchMap(empty); // set it as current keymap
657 KeyTrans.mainKeyMap = KeyTrans.currentKeyMap;
658 }
659 else {
660 string keydef(switchKey);
661 keydef += " !*!*!*"; // just for check
662 WORD vk_code;
663 DWORD control;
664 switchKey = ParseKeyDef(keydef.c_str(),vk_code,control);
665 if ( switchKey != NULL ) {
666 TKeyDef swi(NULL,control,vk_code);
667 if ( KeyTrans.switchMap(swi) > 0 ) {
668 // cerr << "Duplicate switching key\n";
669 printm(0, FALSE, MSG_KEYDUPSWKEY);
670 break;
671 };
672 KeyTrans.mapArray.Add(KeyMap(swi, orig));
673 KeyTrans.switchMap(swi); // set it as current keymap
674 }
675 };
676 mapdef+=7; // 'keymap '
677 // now load defined keymaps to current
678 while ((mapdef != NULL)&&
679 (mapdef = strtok(mapdef,TOKEN_DELIMITERS)) != NULL ) {
680 i = LookForPart(SA,"keymap",mapdef);
681 if ( i == INT_MAX ) {
682 // cerr << "Unknown KEYMAP " << mapdef << endl;
683 printm(0, FALSE, MSG_KEYUNKNOWNMAP, mapdef);
684 } else {
685 mapdef = strtok(NULL,"\n"); // strtok is used in LoadKeyMap
686 // so - save pointer!
687 hadKeys = LoadKeyMap(SA[i]); // load it
688 };
689 };
690
691 }
692 else if ( strnicmp(buf,"charmap",7) == 0 ) {
693 printit("\t"); printit(buf); printit("\n");
694 char * mapdef = buf + 8;// 'charmap '
695 int SuccesLoaded = 0;
696 // now load defined charmaps to current
697 while ((mapdef != NULL)&&
698 (mapdef = strtok(mapdef,TOKEN_DELIMITERS)) != NULL ) {
699 i = LookForPart(SA,"charmap",mapdef);
700 if ( i == INT_MAX ) {
701 // cerr << "Unknown KEYMAP " << mapdef << endl;
702 printm(0, FALSE, MSG_KEYUNKNOWNMAP, mapdef);
703 } else {
704 mapdef = strtok(NULL,"\n"); // strtok is used in LoadKeyMap
705 // so - save pointer!
706 if (LoadCharMap(SA[i])) // load it
707 SuccesLoaded++;
708 };
709 };
710 if (!SuccesLoaded) {
711 // cerr << "No charmaps loaded\n";
712 printm(0, FALSE, MSG_KEYNOCHARMAPS);
713 Charmap.init();
714 };
715 /* strtok(buf," ");
716
717 char* name = strtok(NULL," ");
718 if ( name == NULL ) {
719 cerr << "No name for CHARMAP" << endl;
720 } else {
721 i = LookForPart(SA,"charmap", name);
722 if ( i == INT_MAX ) {
723 cerr << "Unknown CHARMAP " << name << endl;
724 } else {
725 LoadCharMap(SA[i]);
726 };
727 };
728 */
729 }
730 else {
731 // cerr << "unexpected token in " << szActiveEmul << endl;
732 printm(0, FALSE, MSG_KEYUNEXPTOKIN, szActiveEmul);
733 }
734 }
735
736 if ( hadKeys) {
737 TKeyDef empty;
738 KeyTrans.switchMap(empty); // switch to default
739 KeyTrans.mainKeyMap = KeyTrans.currentKeyMap; // save it's number
740 // cerr << "There are " << (KeyTrans.mapArray.GetItemsInContainer()) << " maps\n";
741 char s[12]; // good enough for a long int (32-bit)
742 itoa(KeyTrans.mapArray.GetItemsInContainer(), s, 10);
743 printm(0, FALSE, MSG_KEYNUMMAPS, s);
744 return 1;
745 };
746 return 0;
747 }
748
749 void TMapLoader::Display() {
750
751 int max = KeyTrans.mapArray.GetItemsInContainer();
752 if (max == 0) {
753 printm(0, FALSE, MSG_KEYNOKEYMAPS);
754 return;
755 };
756 for ( int i = 0; i < max; i++ ) {
757 char buf[20];
758 itoa(i,buf,10);
759 printit("\t");
760 // Ioannou : we can show the current
761 if (KeyTrans.currentKeyMap == i)
762 printit("*");
763 else
764 printit(" ");
765 strcat(buf," ");
766 printit(buf);
767 char * msg = new char [KeyTrans.mapArray[i].orig.length()+1];
768 strcpy(msg,KeyTrans.mapArray[i].orig.c_str());
769 printit(msg);
770 delete[] msg;
771 printit("\n");
772 };
773 };