Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

G4UItcsh.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 //
00027 // $Id: G4UItcsh.cc,v 1.12 2006/06/29 19:09:54 gunter Exp $
00028 // GEANT4 tag $Name: geant4-08-01-patch-01 $
00029 //
00030 
00031 #ifndef WIN32
00032 
00033 #include "G4Types.hh"
00034 #include "G4StateManager.hh"
00035 #include "G4UIcommandStatus.hh"
00036 #include "G4UItcsh.hh"
00037 #include <ctype.h>
00038 #include <sstream>
00039 
00040 // ASCII character code
00041 static const char AsciiCtrA = '\001';
00042 static const char AsciiCtrB = '\002';
00043 static const char AsciiCtrC = '\003';
00044 static const char AsciiCtrD = '\004';
00045 static const char AsciiCtrE = '\005';
00046 static const char AsciiCtrF = '\006';
00047 static const char AsciiCtrK = '\013';
00048 static const char AsciiCtrL = '\014';
00049 static const char AsciiCtrN = '\016';
00050 static const char AsciiCtrP = '\020';
00051 static const char AsciiCtrQ = '\021';
00052 static const char AsciiCtrS = '\023';
00053 static const char AsciiCtrZ = '\032';
00054 static const char AsciiTAB   = '\011';
00055 static const char AsciiBS    = '\010';
00056 static const char AsciiDEL   = '\177';
00057 static const char AsciiESC   = '\033';
00058 
00059 static const int AsciiPrintableMin = 32;
00060 
00062 G4UItcsh::G4UItcsh(const G4String& prompt, G4int maxhist)
00063   : G4VUIshell(prompt),
00064     commandLine(""), cursorPosition(1),
00065     commandHistory(maxhist), maxHistory(maxhist),
00066     currentHistoryNo(1), relativeHistoryIndex(0)
00068 {  
00069   // get current terminal mode
00070   tcgetattr(0, &tios);
00071 }
00072 
00074 G4UItcsh::~G4UItcsh()
00076 {
00077 }
00078   
00080 void G4UItcsh::MakePrompt(const char* msg)
00082 {
00083   if(promptSetting.length()<=1) {
00084     promptString= promptSetting;
00085     return;
00086   }
00087 
00088   promptString="";
00089   size_t i;
00090   for(i=0; i<promptSetting.length()-1; i++){
00091     if(promptSetting[i]=='%'){
00092       switch (promptSetting[i+1]) {
00093       case 's':  // current application status
00094         {
00095           G4String stateStr;
00096           if(msg)
00097           { stateStr = msg; }
00098           else
00099           {
00100             G4StateManager* statM= G4StateManager::GetStateManager();
00101             stateStr= statM-> GetStateString(statM->GetCurrentState());
00102           }
00103           promptString.append(stateStr);
00104           i++;
00105         }
00106         break;
00107       case '/':  // current working directory
00108         promptString.append(currentCommandDir);
00109         i++;
00110         break;
00111       case 'h':  // history#
00112         {
00113         std::ostringstream os;
00114         os << currentHistoryNo;
00115         promptString.append(os.str());
00116         i++;
00117         }
00118         break;
00119       default:
00120         break;
00121       } 
00122     } else {
00123       promptString.append(G4String(promptSetting[i]));
00124     }
00125   }
00126 
00127   // append last chaacter
00128   if(i == promptSetting.length()-1) 
00129     promptString.append(G4String(promptSetting[i]));
00130 }
00131 
00132 // --------------------------------------------------------------------
00133 //      commad line operations
00134 // --------------------------------------------------------------------
00136 void G4UItcsh::InitializeCommandLine()
00138 {
00139   commandLine= "";
00140   cursorPosition= 1;
00141 }
00142 
00144 void G4UItcsh::InsertCharacter(char cc)
00146 {
00147   if( ! (cc >= AsciiPrintableMin  && isprint(cc)) ) return;
00148 
00149   // display...
00150   G4cout << cc;
00151   size_t i;
00152   for(i=cursorPosition-1; i<commandLine.length() ;i++) 
00153     G4cout << commandLine[i];
00154   for(i=cursorPosition-1; i<commandLine.length() ;i++)
00155     G4cout << AsciiBS;
00156   G4cout << std::flush;
00157     
00158   // command line string...
00159   if(IsCursorLast()) {  // add
00160     commandLine+= cc;
00161   } else { // insert
00162     commandLine.insert(cursorPosition-1, G4String(cc));
00163   }
00164   cursorPosition++;
00165 }
00166   
00168 void G4UItcsh::BackspaceCharacter()
00170 {
00171   if(cursorPosition==1) return;
00172 
00173   // display...
00174   if(IsCursorLast()) {  
00175     G4cout << AsciiBS << ' ' << AsciiBS << std::flush;
00176   } else { 
00177     G4cout << AsciiBS;
00178     size_t i;
00179     for(i=cursorPosition-2; i< commandLine.length()-1 ;i++){
00180       G4cout << commandLine[i+1];
00181     }
00182     G4cout << ' ';
00183     for(i=cursorPosition-2; i< commandLine.length() ;i++){
00184       G4cout << AsciiBS;
00185     }
00186     G4cout << std::flush;
00187   }
00188 
00189   // command line string...
00190   commandLine.erase(cursorPosition-2, 1);
00191 
00192   cursorPosition--;
00193 }
00194 
00196 void G4UItcsh::DeleteCharacter()
00198 {
00199   if(IsCursorLast()) return;
00200 
00201   // display...
00202   size_t i;
00203   for(i=cursorPosition-1; i< commandLine.length()-1 ;i++){
00204     G4cout << commandLine[i+1];
00205   }
00206   G4cout << ' ';
00207   for(i=cursorPosition-1; i< commandLine.length() ;i++){
00208     G4cout << AsciiBS;
00209   }
00210   G4cout << std::flush;
00211 
00212   // command lin string...
00213   commandLine.erase(cursorPosition-1, 1);
00214 }
00215 
00217 void G4UItcsh::ClearLine()
00219 {
00220   // display...
00221   G4int i;
00222   for(i= cursorPosition; i>=2; i--) G4cout << AsciiBS;
00223   for(i=1; i<=G4int(commandLine.length()); i++) G4cout << ' ';
00224   for(i=1; i<=G4int(commandLine.length()); i++) G4cout << AsciiBS;
00225   G4cout << std::flush;
00226   
00227   // command line string...
00228   commandLine.erase();
00229   cursorPosition= 1;
00230 }
00231 
00233 void G4UItcsh::ClearAfterCursor()
00235 {
00236   if(IsCursorLast()) return;
00237 
00238   // display...
00239   G4int i;
00240   for(i=cursorPosition; i<=G4int(commandLine.length()); i++) G4cout << ' ';
00241   for(i=commandLine.length(); i>=cursorPosition; i--) G4cout << AsciiBS;
00242   G4cout << std::flush;
00243 
00244   // command line string...
00245   commandLine.erase(cursorPosition-1, 
00246                     commandLine.length()-cursorPosition+1);
00247 }
00248 
00250 void G4UItcsh::ClearScreen()
00252 {
00253   if(! clearString.empty() ) {
00254     G4cout << clearString;
00255 
00256     G4cout << promptString << commandLine << std::flush;
00257     // reset cursur position
00258     for(G4int i=commandLine.length()+1; i>=cursorPosition+1; i--) 
00259       G4cout << AsciiBS << std::flush;
00260   }
00261 }
00262 
00264 void G4UItcsh::ForwardCursor()
00266 {
00267   if(IsCursorLast()) return;
00268 
00269   G4cout << commandLine[(size_t)(cursorPosition-1)] << std::flush;
00270   cursorPosition++;
00271 }
00272 
00274 void G4UItcsh::BackwardCursor()
00276 {
00277   if(cursorPosition==1) return;
00278 
00279   cursorPosition--;
00280   G4cout << AsciiBS << std::flush;
00281 }
00282 
00284 void G4UItcsh::MoveCursorTop()
00286 {
00287   for(G4int i=cursorPosition; i>1; i--){
00288     G4cout << AsciiBS;
00289   }
00290   G4cout << std::flush;
00291   cursorPosition=1;
00292 }
00293 
00295 void G4UItcsh::MoveCursorEnd()
00297 {
00298   for(size_t i=cursorPosition-1; i<commandLine.length(); i++){
00299     G4cout << commandLine[i];
00300   }
00301   G4cout << std::flush;
00302   cursorPosition=commandLine.length()+1;
00303 }
00304 
00306 void G4UItcsh::PreviousCommand()
00308 {
00309   G4int nhmax= currentHistoryNo-1 >= maxHistory ? 
00310                  maxHistory : currentHistoryNo-1;
00311 
00312   // retain current input
00313   if(relativeHistoryIndex==0) commandLineBuf= commandLine;
00314 
00315   if(relativeHistoryIndex>=-nhmax+1 && relativeHistoryIndex<=0) {
00316     ClearLine();
00317     relativeHistoryIndex--;
00318     commandLine= RestoreHistory(currentHistoryNo+relativeHistoryIndex);
00319 
00320     G4cout << commandLine << std::flush;
00321     cursorPosition= commandLine.length()+1;
00322   }
00323 }
00324 
00326 void G4UItcsh::NextCommand()
00328 {  
00329   G4int nhmax= currentHistoryNo-1 >= maxHistory ? 
00330                  maxHistory : currentHistoryNo-1;
00331 
00332   if(relativeHistoryIndex>=-nhmax && relativeHistoryIndex<=-1) {
00333     ClearLine();
00334     relativeHistoryIndex++;
00335 
00336     if(relativeHistoryIndex==0) commandLine= commandLineBuf;
00337     else commandLine= RestoreHistory(currentHistoryNo+relativeHistoryIndex);
00338 
00339     G4cout << commandLine << std::flush;      
00340     cursorPosition= commandLine.length()+1;
00341   }
00342 }
00343 
00344 
00346 void G4UItcsh::ListMatchedCommand()
00348 {
00349   G4cout << G4endl;
00350   
00351   // input string
00352   G4String input= G4String(commandLine).strip(G4String::leading);
00353   // target token is last token
00354   G4int jhead= input.last(' ');
00355   if(jhead != G4int(G4String::npos)) {
00356     input.remove(0, jhead);
00357     input= input.strip(G4String::leading);
00358   }
00359 
00360   // command tree of "user specified directory"
00361   G4String vpath= currentCommandDir;
00362   G4String vcmd;
00363 
00364   if( !input.empty() ) {
00365     G4int len= input.length();
00366     G4int indx=-1;
00367     for(G4int i=len-1; i>=0; i--) {
00368       if(input[(size_t)i]=='/') {
00369         indx= i;
00370         break;
00371       }   
00372     }
00373     // get abs. path
00374     if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));  
00375     if(!(indx==0  && len==1)) vcmd= input(indx+1,len-indx-1);  // care for "/"
00376   }
00377 
00378   // list matched dirs/commands
00379   ListCommand(vpath, vpath+vcmd);
00380 
00381   G4cout << promptString << commandLine << std::flush;
00382 }
00383 
00385 void G4UItcsh::CompleteCommand()
00387 {
00388   // inputting string
00389   G4String input= G4String(commandLine).strip(G4String::leading);
00390   // target token is last token
00391   G4int jhead= input.last(' ');
00392   if(jhead != G4int(G4String::npos)) {
00393     input.remove(0, jhead);
00394     input= input.strip(G4String::leading);
00395   }
00396 
00397   // command tree of "user specified directory"  
00398   G4String vpath= currentCommandDir;
00399   G4String vcmd;
00400 
00401   G4int len= input.length();
00402   if(!input.empty()) {
00403     G4int indx= -1;
00404     for(G4int i=len-1; i>=0; i--) {
00405       if(input(i)=='/') {
00406         indx= i;
00407         break;
00408       }   
00409     }
00410     // get abs. path
00411     if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));  
00412     if(!(indx==0  && len==1)) vcmd= input(indx+1,len-indx-1);  // care for "/"
00413   }
00414 
00415   G4UIcommandTree* atree= GetCommandTree(vpath);  // get command tree
00416   if(atree == NULL) return;
00417 
00418   // list matched directories/commands
00419   G4String stream, strtmp;
00420   G4String inputpath= vpath+vcmd;
00421   G4int nMatch= 0;
00422 
00423   int Ndir= atree-> GetTreeEntry();
00424   int Ncmd= atree-> GetCommandEntry();
00425   
00426   // directory ...
00427   for(G4int idir=1; idir<=Ndir; idir++) {
00428     G4String fpdir= atree-> GetTree(idir)-> GetPathName();
00429     // matching test
00430     if( fpdir.index(inputpath, 0) == 0) {
00431       if(nMatch==0) {
00432         stream= GetCommandPathTail(fpdir);
00433       } else {
00434         strtmp= GetCommandPathTail(fpdir);
00435         stream= GetFirstMatchedString(stream, strtmp);
00436       }
00437       nMatch++;
00438     }
00439   }
00440   
00441   // command ...
00442   for(G4int icmd=1; icmd<=Ncmd; icmd++){
00443     G4String fpcmd= atree-> GetPathName() +
00444                     atree-> GetCommand(icmd) -> GetCommandName();
00445     // matching test
00446     if( fpcmd.index(inputpath, 0) ==0) {
00447       if(nMatch==0) {
00448         stream= GetCommandPathTail(fpcmd) + " ";
00449       } else {
00450         strtmp= GetCommandPathTail(fpcmd) + " ";
00451         stream= GetFirstMatchedString(stream, strtmp);
00452       }
00453       nMatch++;
00454     }
00455   }
00456 
00457   if(nMatch==0) return;  // no matched
00458 
00459   // display...
00460   input= commandLine;
00461   // target token is last token
00462   jhead= input.last(' ');
00463   if(jhead == G4int(G4String::npos)) jhead=0;
00464   else jhead++;
00465 
00466   G4int jt= input.find_last_of('/');
00467   if(jt<jhead) jt=G4String::npos;
00468 
00469   if(jt==G4int(G4String::npos)) jt= jhead;
00470   else jt++;
00471 
00472   G4String dspstr; 
00473   G4int i;
00474   for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS); // cleanup
00475   for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(' '); 
00476   for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS); 
00477 
00478   dspstr+= stream;
00479   G4cout << dspstr << std::flush; 
00480 
00481   // command line string
00482   input.remove(jt);
00483   input+= stream;
00484 
00485   commandLine= input;
00486   cursorPosition= commandLine.length()+1;
00487 }
00488 
00489 
00490 // --------------------------------------------------------------------
00491 //      commad line
00492 // --------------------------------------------------------------------
00494 G4String G4UItcsh::ReadLine()
00496 {
00497   InitializeCommandLine();
00498 
00499   char cc;
00500   do{  // input loop
00501     G4cin.get(cc);
00502 
00503     // treatment for special character
00504     switch(cc){
00505     case AsciiCtrA:       // ... move cursor to the top
00506       MoveCursorTop();
00507       break;
00508     case AsciiCtrB:       // ... backward cursor
00509       BackwardCursor();
00510       break;
00511     case AsciiCtrD:       // ... delete/exit/show matched list
00512       if(commandLine.length()!=0 && IsCursorLast()) ListMatchedCommand();
00513       else if (commandLine.empty()) {
00514         G4cout << G4endl;
00515         exit(0);
00516       } else DeleteCharacter();
00517       break;
00518     case AsciiCtrE:       // ... move cursor to the end
00519       MoveCursorEnd();
00520       break;
00521     case AsciiCtrF:       // ... forward cursor
00522       ForwardCursor();
00523       break;
00524     case AsciiCtrK:       // ... clear after the cursor
00525       ClearAfterCursor();
00526       break;
00527     case AsciiCtrL:       // ... clear screen
00528       // ClearScreen();
00529       break;
00530     case AsciiCtrN:     // ... next command
00531       NextCommand();
00532       break;
00533     case AsciiCtrP:     // ... previous command
00534       PreviousCommand();
00535       break;
00536     case AsciiTAB:         // ... command completion
00537       if( (!commandLine.empty()) && IsCursorLast()) CompleteCommand();
00538       break;
00539     case AsciiDEL:         // ... backspace
00540       BackspaceCharacter();
00541       break;
00542     case AsciiBS:          // ... backspace
00543       BackspaceCharacter();
00544       break;
00545     case AsciiCtrC:       // ... kill prompt
00546       break;
00547     case AsciiCtrQ:       // ... restarts suspeded output
00548       break;
00549     case AsciiCtrS:       // ... suspend output
00550       break;
00551     case AsciiCtrZ:       // ... suspend
00552       break;
00553     default:
00554       break;
00555     }
00556 
00557     // treatment for ESC. character
00558     if( cc == AsciiESC) { // ESC
00559       G4cin.get(cc);
00560       if (cc == '[' || 'O') { // care for another termcap, such as konsole
00561         G4cin.get(cc);
00562         switch(cc) {
00563         case 'A': // [UP]
00564           cc = 'P' - '@';
00565           PreviousCommand();  // ... show previous commad
00566           break;
00567         case 'B': // [DOWN]
00568           cc = 'N' - '@';
00569           NextCommand();  // ... show next commad
00570           break;
00571         case 'C': // [RIGHT]
00572           cc = 'F' - '@';
00573           ForwardCursor();   // ... forward cursor
00574           break;
00575         case 'D': // [LEFT]
00576           cc = 'B' - '@';
00577           BackwardCursor();      // ... backward cursor
00578           break;
00579         default:  // who knows !?
00580           cc = 0;
00581           break;
00582         }
00583       }
00584     }
00585 
00586     // insert character to command line and display
00587     InsertCharacter(cc);
00588   
00589   } while( cc != '\n');
00590 
00591   return commandLine;
00592 }
00593 
00595 G4String G4UItcsh::GetCommandLine(const char* msg)
00597 {
00598   SetTermToInputMode();
00599 
00600   MakePrompt(msg); // update
00601   relativeHistoryIndex= 0;
00602 
00603   G4cout << promptString << std::flush;
00604 
00605   G4String newCommand= ReadLine();  // read line...
00606   // multi-line
00607   while( (newCommand.length() > 0) &&
00608          ( newCommand[newCommand.length()-1] == '_') ) {
00609     newCommand.remove(newCommand.length()-1);
00610     G4cout << G4endl;
00611     promptString= "? ";
00612     G4cout << promptString << std::flush;
00613     G4String newLine= ReadLine();
00614     newCommand.append(newLine);
00615   }
00616 
00617   // update history...
00618   G4bool isMeaningfull= FALSE; // check NULL command
00619   for (size_t i=0; i<newCommand.length(); i++) {
00620     if(newCommand[i] != ' ') {
00621       isMeaningfull= TRUE;
00622       break;
00623     }
00624   }
00625   if( !newCommand.empty() && isMeaningfull) StoreHistory(newCommand);
00626 
00627   // reset terminal
00628   RestoreTerm();
00629 
00630   G4cout << G4endl;
00631   return newCommand;
00632 }
00633 
00635 G4String G4UItcsh::GetFirstMatchedString(const G4String& str1, 
00636                                          const G4String& str2) const
00638 {
00639   int nlen1= str1.length();
00640   int nlen2= str2.length();
00641 
00642   int nmin = nlen1<nlen2 ? nlen1 : nlen2;
00643 
00644   G4String strMatched;
00645   for(size_t i=0; G4int(i)<nmin; i++){
00646     if(str1[i]==str2[i]) {
00647       strMatched+= str1[i];
00648     } else {
00649       break;
00650     }
00651   }
00652 
00653   return strMatched;
00654 }
00655 
00656 // --------------------------------------------------------------------
00657 //      history
00658 // --------------------------------------------------------------------
00660 void G4UItcsh::StoreHistory(G4String aCommand)
00662 {
00663   G4int i= currentHistoryNo%maxHistory; 
00664   if(i==0) i=maxHistory;
00665 
00666   commandHistory[i-1]= aCommand;  // 0-offset
00667   currentHistoryNo++;
00668 }
00669 
00671 G4String G4UItcsh::RestoreHistory(G4int histNo)
00673 {
00674   if(histNo>= currentHistoryNo) return "";
00675 
00676   G4int index= histNo%maxHistory;
00677   if(index==0) index= maxHistory;
00678 
00679   return commandHistory[index-1]; // 0-offset
00680 }
00681 
00682 // --------------------------------------------------------------------
00683 //      terminal mode
00684 // --------------------------------------------------------------------
00686 void G4UItcsh::SetTermToInputMode()
00688 {  
00689   termios tiosbuf= tios;
00690 
00691   tiosbuf.c_iflag &= ~(BRKINT | ISTRIP);
00692   tiosbuf.c_iflag |= (IGNBRK | IGNPAR);
00693   tiosbuf.c_lflag &= ~(ICANON | IEXTEN | ECHO);
00694   tiosbuf.c_cc[VMIN] = 1;
00695   tiosbuf.c_cc[VTIME] = 0;
00696   
00697   tcsetattr(0, TCSAFLUSH, &tiosbuf);
00698 }
00699 
00700 
00702 void G4UItcsh::RestoreTerm()
00704 {
00705   tcsetattr(0, TCSAFLUSH, &tios);
00706 }  
00707 
00708 #endif
00709 

Generated on Fri Jun 22 11:07:02 2007 by doxygen 1.3.4