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

Last change on this file since 1156 was 1156, checked in by garnier, 15 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.