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