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