source: trunk/source/interfaces/basic/src/G4UItcsh.cc@ 1281

Last change on this file since 1281 was 1156, checked in by garnier, 16 years ago

append qt3 fix

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