source: trunk/geant4/interfaces/basic/src/G4UItcsh.cc@ 540

Last change on this file since 540 was 483, checked in by garnier, 18 years ago

r569@mac-90108: laurentgarnier | 2007-06-05 15:53:34 +0200
version contre geant4.8.2.p01

File size: 18.4 KB
Line 
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26//
27// $Id: G4UItcsh.cc,v 1.12 2006/06/29 19:09:54 gunter Exp $
28// GEANT4 tag $Name: geant4-08-01-patch-01 $
29//
30
31#ifndef WIN32
32
33#include "G4Types.hh"
34#include "G4StateManager.hh"
35#include "G4UIcommandStatus.hh"
36#include "G4UItcsh.hh"
37#include <ctype.h>
38#include <sstream>
39
40// ASCII character code
41static const char AsciiCtrA = '\001';
42static const char AsciiCtrB = '\002';
43static const char AsciiCtrC = '\003';
44static const char AsciiCtrD = '\004';
45static const char AsciiCtrE = '\005';
46static const char AsciiCtrF = '\006';
47static const char AsciiCtrK = '\013';
48static const char AsciiCtrL = '\014';
49static const char AsciiCtrN = '\016';
50static const char AsciiCtrP = '\020';
51static const char AsciiCtrQ = '\021';
52static const char AsciiCtrS = '\023';
53static const char AsciiCtrZ = '\032';
54static const char AsciiTAB = '\011';
55static const char AsciiBS = '\010';
56static const char AsciiDEL = '\177';
57static const char AsciiESC = '\033';
58
59static const int AsciiPrintableMin = 32;
60
61/////////////////////////////////////////////////////////
62G4UItcsh::G4UItcsh(const G4String& prompt, G4int maxhist)
63 : G4VUIshell(prompt),
64 commandLine(""), cursorPosition(1),
65 commandHistory(maxhist), maxHistory(maxhist),
66 currentHistoryNo(1), relativeHistoryIndex(0)
67/////////////////////////////////////////////////////////
68{
69 // get current terminal mode
70 tcgetattr(0, &tios);
71}
72
73/////////////////////
74G4UItcsh::~G4UItcsh()
75/////////////////////
76{
77}
78
79///////////////////////////
80void G4UItcsh::MakePrompt(const char* msg)
81///////////////////////////
82{
83 if(promptSetting.length()<=1) {
84 promptString= promptSetting;
85 return;
86 }
87
88 promptString="";
89 size_t i;
90 for(i=0; i<promptSetting.length()-1; i++){
91 if(promptSetting[i]=='%'){
92 switch (promptSetting[i+1]) {
93 case 's': // current application status
94 {
95 G4String stateStr;
96 if(msg)
97 { stateStr = msg; }
98 else
99 {
100 G4StateManager* statM= G4StateManager::GetStateManager();
101 stateStr= statM-> GetStateString(statM->GetCurrentState());
102 }
103 promptString.append(stateStr);
104 i++;
105 }
106 break;
107 case '/': // current working directory
108 promptString.append(currentCommandDir);
109 i++;
110 break;
111 case 'h': // history#
112 {
113 std::ostringstream os;
114 os << currentHistoryNo;
115 promptString.append(os.str());
116 i++;
117 }
118 break;
119 default:
120 break;
121 }
122 } else {
123 promptString.append(G4String(promptSetting[i]));
124 }
125 }
126
127 // append last chaacter
128 if(i == promptSetting.length()-1)
129 promptString.append(G4String(promptSetting[i]));
130}
131
132// --------------------------------------------------------------------
133// commad line operations
134// --------------------------------------------------------------------
135//////////////////////////////////////
136void G4UItcsh::InitializeCommandLine()
137//////////////////////////////////////
138{
139 commandLine= "";
140 cursorPosition= 1;
141}
142
143///////////////////////////////////////
144void G4UItcsh::InsertCharacter(char cc)
145///////////////////////////////////////
146{
147 if( ! (cc >= AsciiPrintableMin && isprint(cc)) ) return;
148
149 // display...
150 G4cout << cc;
151 size_t i;
152 for(i=cursorPosition-1; i<commandLine.length() ;i++)
153 G4cout << commandLine[i];
154 for(i=cursorPosition-1; i<commandLine.length() ;i++)
155 G4cout << AsciiBS;
156 G4cout << std::flush;
157
158 // command line string...
159 if(IsCursorLast()) { // add
160 commandLine+= cc;
161 } else { // insert
162 commandLine.insert(cursorPosition-1, G4String(cc));
163 }
164 cursorPosition++;
165}
166
167///////////////////////////////////
168void G4UItcsh::BackspaceCharacter()
169///////////////////////////////////
170{
171 if(cursorPosition==1) return;
172
173 // display...
174 if(IsCursorLast()) {
175 G4cout << AsciiBS << ' ' << AsciiBS << std::flush;
176 } else {
177 G4cout << AsciiBS;
178 size_t i;
179 for(i=cursorPosition-2; i< commandLine.length()-1 ;i++){
180 G4cout << commandLine[i+1];
181 }
182 G4cout << ' ';
183 for(i=cursorPosition-2; i< commandLine.length() ;i++){
184 G4cout << AsciiBS;
185 }
186 G4cout << std::flush;
187 }
188
189 // command line string...
190 commandLine.erase(cursorPosition-2, 1);
191
192 cursorPosition--;
193}
194
195////////////////////////////////
196void G4UItcsh::DeleteCharacter()
197////////////////////////////////
198{
199 if(IsCursorLast()) return;
200
201 // display...
202 size_t i;
203 for(i=cursorPosition-1; i< commandLine.length()-1 ;i++){
204 G4cout << commandLine[i+1];
205 }
206 G4cout << ' ';
207 for(i=cursorPosition-1; i< commandLine.length() ;i++){
208 G4cout << AsciiBS;
209 }
210 G4cout << std::flush;
211
212 // command lin string...
213 commandLine.erase(cursorPosition-1, 1);
214}
215
216//////////////////////////
217void G4UItcsh::ClearLine()
218//////////////////////////
219{
220 // display...
221 G4int i;
222 for(i= cursorPosition; i>=2; i--) G4cout << AsciiBS;
223 for(i=1; i<=G4int(commandLine.length()); i++) G4cout << ' ';
224 for(i=1; i<=G4int(commandLine.length()); i++) G4cout << AsciiBS;
225 G4cout << std::flush;
226
227 // command line string...
228 commandLine.erase();
229 cursorPosition= 1;
230}
231
232/////////////////////////////////
233void G4UItcsh::ClearAfterCursor()
234/////////////////////////////////
235{
236 if(IsCursorLast()) return;
237
238 // display...
239 G4int i;
240 for(i=cursorPosition; i<=G4int(commandLine.length()); i++) G4cout << ' ';
241 for(i=commandLine.length(); i>=cursorPosition; i--) G4cout << AsciiBS;
242 G4cout << std::flush;
243
244 // command line string...
245 commandLine.erase(cursorPosition-1,
246 commandLine.length()-cursorPosition+1);
247}
248
249////////////////////////////
250void G4UItcsh::ClearScreen()
251////////////////////////////
252{
253 if(! clearString.empty() ) {
254 G4cout << clearString;
255
256 G4cout << promptString << commandLine << std::flush;
257 // reset cursur position
258 for(G4int i=commandLine.length()+1; i>=cursorPosition+1; i--)
259 G4cout << AsciiBS << std::flush;
260 }
261}
262
263//////////////////////////////
264void G4UItcsh::ForwardCursor()
265//////////////////////////////
266{
267 if(IsCursorLast()) return;
268
269 G4cout << commandLine[(size_t)(cursorPosition-1)] << std::flush;
270 cursorPosition++;
271}
272
273///////////////////////////////
274void G4UItcsh::BackwardCursor()
275///////////////////////////////
276{
277 if(cursorPosition==1) return;
278
279 cursorPosition--;
280 G4cout << AsciiBS << std::flush;
281}
282
283//////////////////////////////
284void G4UItcsh::MoveCursorTop()
285//////////////////////////////
286{
287 for(G4int i=cursorPosition; i>1; i--){
288 G4cout << AsciiBS;
289 }
290 G4cout << std::flush;
291 cursorPosition=1;
292}
293
294//////////////////////////////
295void G4UItcsh::MoveCursorEnd()
296//////////////////////////////
297{
298 for(size_t i=cursorPosition-1; i<commandLine.length(); i++){
299 G4cout << commandLine[i];
300 }
301 G4cout << std::flush;
302 cursorPosition=commandLine.length()+1;
303}
304
305////////////////////////////////
306void G4UItcsh::PreviousCommand()
307////////////////////////////////
308{
309 G4int nhmax= currentHistoryNo-1 >= maxHistory ?
310 maxHistory : currentHistoryNo-1;
311
312 // retain current input
313 if(relativeHistoryIndex==0) commandLineBuf= commandLine;
314
315 if(relativeHistoryIndex>=-nhmax+1 && relativeHistoryIndex<=0) {
316 ClearLine();
317 relativeHistoryIndex--;
318 commandLine= RestoreHistory(currentHistoryNo+relativeHistoryIndex);
319
320 G4cout << commandLine << std::flush;
321 cursorPosition= commandLine.length()+1;
322 }
323}
324
325////////////////////////////
326void G4UItcsh::NextCommand()
327////////////////////////////
328{
329 G4int nhmax= currentHistoryNo-1 >= maxHistory ?
330 maxHistory : currentHistoryNo-1;
331
332 if(relativeHistoryIndex>=-nhmax && relativeHistoryIndex<=-1) {
333 ClearLine();
334 relativeHistoryIndex++;
335
336 if(relativeHistoryIndex==0) commandLine= commandLineBuf;
337 else commandLine= RestoreHistory(currentHistoryNo+relativeHistoryIndex);
338
339 G4cout << commandLine << std::flush;
340 cursorPosition= commandLine.length()+1;
341 }
342}
343
344
345///////////////////////////////////
346void G4UItcsh::ListMatchedCommand()
347///////////////////////////////////
348{
349 G4cout << G4endl;
350
351 // input string
352 G4String input= G4String(commandLine).strip(G4String::leading);
353 // target token is last token
354 G4int jhead= input.last(' ');
355 if(jhead != G4int(G4String::npos)) {
356 input.remove(0, jhead);
357 input= input.strip(G4String::leading);
358 }
359
360 // command tree of "user specified directory"
361 G4String vpath= currentCommandDir;
362 G4String vcmd;
363
364 if( !input.empty() ) {
365 G4int len= input.length();
366 G4int indx=-1;
367 for(G4int i=len-1; i>=0; i--) {
368 if(input[(size_t)i]=='/') {
369 indx= i;
370 break;
371 }
372 }
373 // get abs. path
374 if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));
375 if(!(indx==0 && len==1)) vcmd= input(indx+1,len-indx-1); // care for "/"
376 }
377
378 // list matched dirs/commands
379 ListCommand(vpath, vpath+vcmd);
380
381 G4cout << promptString << commandLine << std::flush;
382}
383
384////////////////////////////////
385void G4UItcsh::CompleteCommand()
386////////////////////////////////
387{
388 // inputting string
389 G4String input= G4String(commandLine).strip(G4String::leading);
390 // target token is last token
391 G4int jhead= input.last(' ');
392 if(jhead != G4int(G4String::npos)) {
393 input.remove(0, jhead);
394 input= input.strip(G4String::leading);
395 }
396
397 // command tree of "user specified directory"
398 G4String vpath= currentCommandDir;
399 G4String vcmd;
400
401 G4int len= input.length();
402 if(!input.empty()) {
403 G4int indx= -1;
404 for(G4int i=len-1; i>=0; i--) {
405 if(input(i)=='/') {
406 indx= i;
407 break;
408 }
409 }
410 // get abs. path
411 if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));
412 if(!(indx==0 && len==1)) vcmd= input(indx+1,len-indx-1); // care for "/"
413 }
414
415 G4UIcommandTree* atree= GetCommandTree(vpath); // get command tree
416 if(atree == NULL) return;
417
418 // list matched directories/commands
419 G4String stream, strtmp;
420 G4String inputpath= vpath+vcmd;
421 G4int nMatch= 0;
422
423 int Ndir= atree-> GetTreeEntry();
424 int Ncmd= atree-> GetCommandEntry();
425
426 // directory ...
427 for(G4int idir=1; idir<=Ndir; idir++) {
428 G4String fpdir= atree-> GetTree(idir)-> GetPathName();
429 // matching test
430 if( fpdir.index(inputpath, 0) == 0) {
431 if(nMatch==0) {
432 stream= GetCommandPathTail(fpdir);
433 } else {
434 strtmp= GetCommandPathTail(fpdir);
435 stream= GetFirstMatchedString(stream, strtmp);
436 }
437 nMatch++;
438 }
439 }
440
441 // command ...
442 for(G4int icmd=1; icmd<=Ncmd; icmd++){
443 G4String fpcmd= atree-> GetPathName() +
444 atree-> GetCommand(icmd) -> GetCommandName();
445 // matching test
446 if( fpcmd.index(inputpath, 0) ==0) {
447 if(nMatch==0) {
448 stream= GetCommandPathTail(fpcmd) + " ";
449 } else {
450 strtmp= GetCommandPathTail(fpcmd) + " ";
451 stream= GetFirstMatchedString(stream, strtmp);
452 }
453 nMatch++;
454 }
455 }
456
457 if(nMatch==0) return; // no matched
458
459 // display...
460 input= commandLine;
461 // target token is last token
462 jhead= input.last(' ');
463 if(jhead == G4int(G4String::npos)) jhead=0;
464 else jhead++;
465
466 G4int jt= input.find_last_of('/');
467 if(jt<jhead) jt=G4String::npos;
468
469 if(jt==G4int(G4String::npos)) jt= jhead;
470 else jt++;
471
472 G4String dspstr;
473 G4int i;
474 for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS); // cleanup
475 for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(' ');
476 for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS);
477
478 dspstr+= stream;
479 G4cout << dspstr << std::flush;
480
481 // command line string
482 input.remove(jt);
483 input+= stream;
484
485 commandLine= input;
486 cursorPosition= commandLine.length()+1;
487}
488
489
490// --------------------------------------------------------------------
491// commad line
492// --------------------------------------------------------------------
493/////////////////////////////
494G4String G4UItcsh::ReadLine()
495/////////////////////////////
496{
497 InitializeCommandLine();
498
499 char cc;
500 do{ // input loop
501 G4cin.get(cc);
502
503 // treatment for special character
504 switch(cc){
505 case AsciiCtrA: // ... move cursor to the top
506 MoveCursorTop();
507 break;
508 case AsciiCtrB: // ... backward cursor
509 BackwardCursor();
510 break;
511 case AsciiCtrD: // ... delete/exit/show matched list
512 if(commandLine.length()!=0 && IsCursorLast()) ListMatchedCommand();
513 else if (commandLine.empty()) {
514 G4cout << G4endl;
515 exit(0);
516 } else DeleteCharacter();
517 break;
518 case AsciiCtrE: // ... move cursor to the end
519 MoveCursorEnd();
520 break;
521 case AsciiCtrF: // ... forward cursor
522 ForwardCursor();
523 break;
524 case AsciiCtrK: // ... clear after the cursor
525 ClearAfterCursor();
526 break;
527 case AsciiCtrL: // ... clear screen
528 // ClearScreen();
529 break;
530 case AsciiCtrN: // ... next command
531 NextCommand();
532 break;
533 case AsciiCtrP: // ... previous command
534 PreviousCommand();
535 break;
536 case AsciiTAB: // ... command completion
537 if( (!commandLine.empty()) && IsCursorLast()) CompleteCommand();
538 break;
539 case AsciiDEL: // ... backspace
540 BackspaceCharacter();
541 break;
542 case AsciiBS: // ... backspace
543 BackspaceCharacter();
544 break;
545 case AsciiCtrC: // ... kill prompt
546 break;
547 case AsciiCtrQ: // ... restarts suspeded output
548 break;
549 case AsciiCtrS: // ... suspend output
550 break;
551 case AsciiCtrZ: // ... suspend
552 break;
553 default:
554 break;
555 }
556
557 // treatment for ESC. character
558 if( cc == AsciiESC) { // ESC
559 G4cin.get(cc);
560 if (cc == '[' || 'O') { // care for another termcap, such as konsole
561 G4cin.get(cc);
562 switch(cc) {
563 case 'A': // [UP]
564 cc = 'P' - '@';
565 PreviousCommand(); // ... show previous commad
566 break;
567 case 'B': // [DOWN]
568 cc = 'N' - '@';
569 NextCommand(); // ... show next commad
570 break;
571 case 'C': // [RIGHT]
572 cc = 'F' - '@';
573 ForwardCursor(); // ... forward cursor
574 break;
575 case 'D': // [LEFT]
576 cc = 'B' - '@';
577 BackwardCursor(); // ... backward cursor
578 break;
579 default: // who knows !?
580 cc = 0;
581 break;
582 }
583 }
584 }
585
586 // insert character to command line and display
587 InsertCharacter(cc);
588
589 } while( cc != '\n');
590
591 return commandLine;
592}
593
594///////////////////////////////////
595G4String G4UItcsh::GetCommandLine(const char* msg)
596///////////////////////////////////
597{
598 SetTermToInputMode();
599
600 MakePrompt(msg); // update
601 relativeHistoryIndex= 0;
602
603 G4cout << promptString << std::flush;
604
605 G4String newCommand= ReadLine(); // read line...
606 // multi-line
607 while( (newCommand.length() > 0) &&
608 ( newCommand[newCommand.length()-1] == '_') ) {
609 newCommand.remove(newCommand.length()-1);
610 G4cout << G4endl;
611 promptString= "? ";
612 G4cout << promptString << std::flush;
613 G4String newLine= ReadLine();
614 newCommand.append(newLine);
615 }
616
617 // update history...
618 G4bool isMeaningfull= FALSE; // check NULL command
619 for (size_t i=0; i<newCommand.length(); i++) {
620 if(newCommand[i] != ' ') {
621 isMeaningfull= TRUE;
622 break;
623 }
624 }
625 if( !newCommand.empty() && isMeaningfull) StoreHistory(newCommand);
626
627 // reset terminal
628 RestoreTerm();
629
630 G4cout << G4endl;
631 return newCommand;
632}
633
634////////////////////////////////////////////////////////////////////
635G4String G4UItcsh::GetFirstMatchedString(const G4String& str1,
636 const G4String& str2) const
637////////////////////////////////////////////////////////////////////
638{
639 int nlen1= str1.length();
640 int nlen2= str2.length();
641
642 int nmin = nlen1<nlen2 ? nlen1 : nlen2;
643
644 G4String strMatched;
645 for(size_t i=0; G4int(i)<nmin; i++){
646 if(str1[i]==str2[i]) {
647 strMatched+= str1[i];
648 } else {
649 break;
650 }
651 }
652
653 return strMatched;
654}
655
656// --------------------------------------------------------------------
657// history
658// --------------------------------------------------------------------
659//////////////////////////////////////////////
660void G4UItcsh::StoreHistory(G4String aCommand)
661//////////////////////////////////////////////
662{
663 G4int i= currentHistoryNo%maxHistory;
664 if(i==0) i=maxHistory;
665
666 commandHistory[i-1]= aCommand; // 0-offset
667 currentHistoryNo++;
668}
669
670///////////////////////////////////////////////
671G4String G4UItcsh::RestoreHistory(G4int histNo)
672///////////////////////////////////////////////
673{
674 if(histNo>= currentHistoryNo) return "";
675
676 G4int index= histNo%maxHistory;
677 if(index==0) index= maxHistory;
678
679 return commandHistory[index-1]; // 0-offset
680}
681
682// --------------------------------------------------------------------
683// terminal mode
684// --------------------------------------------------------------------
685///////////////////////////////////
686void G4UItcsh::SetTermToInputMode()
687///////////////////////////////////
688{
689 termios tiosbuf= tios;
690
691 tiosbuf.c_iflag &= ~(BRKINT | ISTRIP);
692 tiosbuf.c_iflag |= (IGNBRK | IGNPAR);
693 tiosbuf.c_lflag &= ~(ICANON | IEXTEN | ECHO);
694 tiosbuf.c_cc[VMIN] = 1;
695 tiosbuf.c_cc[VTIME] = 0;
696
697 tcsetattr(0, TCSAFLUSH, &tiosbuf);
698}
699
700
701////////////////////////////
702void G4UItcsh::RestoreTerm()
703////////////////////////////
704{
705 tcsetattr(0, TCSAFLUSH, &tios);
706}
707
708#endif
709
Note: See TracBrowser for help on using the repository browser.