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