00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifndef WIN32
00031
00032 #include "G4Types.hh"
00033 #include "G4StateManager.hh"
00034 #include "G4UIcommandStatus.hh"
00035 #include "G4UItcsh.hh"
00036 #include <ctype.h>
00037 #include <sstream>
00038 #include <fstream>
00039 #include <stdlib.h>
00040
00041
00042 static const char AsciiCtrA = '\001';
00043 static const char AsciiCtrB = '\002';
00044 static const char AsciiCtrC = '\003';
00045 static const char AsciiCtrD = '\004';
00046 static const char AsciiCtrE = '\005';
00047 static const char AsciiCtrF = '\006';
00048 static const char AsciiCtrK = '\013';
00049 static const char AsciiCtrL = '\014';
00050 static const char AsciiCtrN = '\016';
00051 static const char AsciiCtrP = '\020';
00052 static const char AsciiCtrQ = '\021';
00053 static const char AsciiCtrS = '\023';
00054 static const char AsciiCtrZ = '\032';
00055 static const char AsciiTAB = '\011';
00056 static const char AsciiBS = '\010';
00057 static const char AsciiDEL = '\177';
00058 static const char AsciiESC = '\033';
00059
00060 static const int AsciiPrintableMin = 32;
00061
00062
00063 static const G4String historyFileName= "/.g4_hist";
00064
00066 G4UItcsh::G4UItcsh(const G4String& prompt, G4int maxhist)
00067 : G4VUIshell(prompt),
00068 commandLine(""), cursorPosition(1),
00069 commandHistory(maxhist), maxHistory(maxhist),
00070 currentHistoryNo(1), relativeHistoryIndex(0)
00072 {
00073
00074 tcgetattr(0, &tios);
00075
00076
00077 const char* path = getenv("HOME");
00078 if( path == NULL ) return;
00079
00080 G4String homedir= path;
00081 G4String fname= homedir + historyFileName;
00082
00083 std::ifstream histfile;
00084 enum { BUFSIZE= 1024 }; char linebuf[BUFSIZE];
00085
00086 histfile.open(fname, std::ios::in);
00087 while (histfile.good()) {
00088 if(histfile.eof()) break;
00089
00090 histfile.getline(linebuf, BUFSIZE);
00091 G4String aline= linebuf;
00092 aline.strip(G4String::both);
00093 if(aline.size() != 0) StoreHistory(linebuf);
00094 }
00095 histfile.close();
00096 }
00097
00099 G4UItcsh::~G4UItcsh()
00101 {
00102
00103 const char* path = getenv("HOME");
00104 if( path == NULL ) return;
00105
00106 G4String homedir= path;
00107 G4String fname= homedir + historyFileName;
00108
00109 std::ofstream histfile;
00110 histfile.open(fname, std::ios::out);
00111
00112 G4int n0hist= 1;
00113 if( currentHistoryNo > maxHistory ) n0hist= currentHistoryNo-maxHistory+1;
00114
00115 for (G4int i=n0hist; i<= currentHistoryNo; i++) {
00116 histfile << RestoreHistory(i) << G4endl;
00117 }
00118
00119 histfile.close();
00120 }
00121
00123 void G4UItcsh::MakePrompt(const char* msg)
00125 {
00126 if(promptSetting.length()<=1) {
00127 promptString= promptSetting;
00128 return;
00129 }
00130
00131 promptString="";
00132 size_t i;
00133 for(i=0; i<promptSetting.length()-1; i++){
00134 if(promptSetting[i]=='%'){
00135 switch (promptSetting[i+1]) {
00136 case 's':
00137 {
00138 G4String stateStr;
00139 if(msg)
00140 { stateStr = msg; }
00141 else
00142 {
00143 G4StateManager* statM= G4StateManager::GetStateManager();
00144 stateStr= statM-> GetStateString(statM->GetCurrentState());
00145 }
00146 promptString.append(stateStr);
00147 i++;
00148 }
00149 break;
00150 case '/':
00151 promptString.append(currentCommandDir);
00152 i++;
00153 break;
00154 case 'h':
00155 {
00156 std::ostringstream os;
00157 os << currentHistoryNo;
00158 promptString.append(os.str());
00159 i++;
00160 }
00161 break;
00162 default:
00163 break;
00164 }
00165 } else {
00166 promptString.append(G4String(promptSetting[i]));
00167 }
00168 }
00169
00170
00171 if(i == promptSetting.length()-1)
00172 promptString.append(G4String(promptSetting[i]));
00173 }
00174
00175
00177 void G4UItcsh::ResetTerminal()
00179 {
00180 RestoreTerm();
00181 }
00182
00183
00184
00185
00186
00188 void G4UItcsh::InitializeCommandLine()
00190 {
00191 commandLine= "";
00192 cursorPosition= 1;
00193 }
00194
00196 void G4UItcsh::InsertCharacter(char cc)
00198 {
00199 if( ! (cc >= AsciiPrintableMin && isprint(cc)) ) return;
00200
00201
00202 G4cout << cc;
00203 size_t i;
00204 for(i=cursorPosition-1; i<commandLine.length() ;i++)
00205 G4cout << commandLine[i];
00206 for(i=cursorPosition-1; i<commandLine.length() ;i++)
00207 G4cout << AsciiBS;
00208 G4cout << std::flush;
00209
00210
00211 if(IsCursorLast()) {
00212 commandLine+= cc;
00213 } else {
00214 commandLine.insert(cursorPosition-1, G4String(cc));
00215 }
00216 cursorPosition++;
00217 }
00218
00220 void G4UItcsh::BackspaceCharacter()
00222 {
00223 if(cursorPosition==1) return;
00224
00225
00226 if(IsCursorLast()) {
00227 G4cout << AsciiBS << ' ' << AsciiBS << std::flush;
00228 } else {
00229 G4cout << AsciiBS;
00230 size_t i;
00231 for(i=cursorPosition-2; i< commandLine.length()-1 ;i++){
00232 G4cout << commandLine[i+1];
00233 }
00234 G4cout << ' ';
00235 for(i=cursorPosition-2; i< commandLine.length() ;i++){
00236 G4cout << AsciiBS;
00237 }
00238 G4cout << std::flush;
00239 }
00240
00241
00242 commandLine.erase(cursorPosition-2, 1);
00243
00244 cursorPosition--;
00245 }
00246
00248 void G4UItcsh::DeleteCharacter()
00250 {
00251 if(IsCursorLast()) return;
00252
00253
00254 size_t i;
00255 for(i=cursorPosition-1; i< commandLine.length()-1 ;i++){
00256 G4cout << commandLine[i+1];
00257 }
00258 G4cout << ' ';
00259 for(i=cursorPosition-1; i< commandLine.length() ;i++){
00260 G4cout << AsciiBS;
00261 }
00262 G4cout << std::flush;
00263
00264
00265 commandLine.erase(cursorPosition-1, 1);
00266 }
00267
00269 void G4UItcsh::ClearLine()
00271 {
00272
00273 G4int i;
00274 for(i= cursorPosition; i>=2; i--) G4cout << AsciiBS;
00275 for(i=1; i<=G4int(commandLine.length()); i++) G4cout << ' ';
00276 for(i=1; i<=G4int(commandLine.length()); i++) G4cout << AsciiBS;
00277 G4cout << std::flush;
00278
00279
00280 commandLine.erase();
00281 cursorPosition= 1;
00282 }
00283
00285 void G4UItcsh::ClearAfterCursor()
00287 {
00288 if(IsCursorLast()) return;
00289
00290
00291 G4int i;
00292 for(i=cursorPosition; i<=G4int(commandLine.length()); i++) G4cout << ' ';
00293 for(i=commandLine.length(); i>=cursorPosition; i--) G4cout << AsciiBS;
00294 G4cout << std::flush;
00295
00296
00297 commandLine.erase(cursorPosition-1,
00298 commandLine.length()-cursorPosition+1);
00299 }
00300
00302 void G4UItcsh::ClearScreen()
00304 {
00305 if(! clearString.empty() ) {
00306 G4cout << clearString;
00307
00308 G4cout << promptString << commandLine << std::flush;
00309
00310 for(G4int i=commandLine.length()+1; i>=cursorPosition+1; i--)
00311 G4cout << AsciiBS << std::flush;
00312 }
00313 }
00314
00316 void G4UItcsh::ForwardCursor()
00318 {
00319 if(IsCursorLast()) return;
00320
00321 G4cout << commandLine[(size_t)(cursorPosition-1)] << std::flush;
00322 cursorPosition++;
00323 }
00324
00326 void G4UItcsh::BackwardCursor()
00328 {
00329 if(cursorPosition==1) return;
00330
00331 cursorPosition--;
00332 G4cout << AsciiBS << std::flush;
00333 }
00334
00336 void G4UItcsh::MoveCursorTop()
00338 {
00339 for(G4int i=cursorPosition; i>1; i--){
00340 G4cout << AsciiBS;
00341 }
00342 G4cout << std::flush;
00343 cursorPosition=1;
00344 }
00345
00347 void G4UItcsh::MoveCursorEnd()
00349 {
00350 for(size_t i=cursorPosition-1; i<commandLine.length(); i++){
00351 G4cout << commandLine[i];
00352 }
00353 G4cout << std::flush;
00354 cursorPosition=commandLine.length()+1;
00355 }
00356
00358 void G4UItcsh::PreviousCommand()
00360 {
00361 G4int nhmax= currentHistoryNo-1 >= maxHistory ?
00362 maxHistory : currentHistoryNo-1;
00363
00364
00365 if(relativeHistoryIndex==0) commandLineBuf= commandLine;
00366
00367 if(relativeHistoryIndex>=-nhmax+1 && relativeHistoryIndex<=0) {
00368 ClearLine();
00369 relativeHistoryIndex--;
00370 commandLine= RestoreHistory(currentHistoryNo+relativeHistoryIndex);
00371
00372 G4cout << commandLine << std::flush;
00373 cursorPosition= commandLine.length()+1;
00374 }
00375 }
00376
00378 void G4UItcsh::NextCommand()
00380 {
00381 G4int nhmax= currentHistoryNo-1 >= maxHistory ?
00382 maxHistory : currentHistoryNo-1;
00383
00384 if(relativeHistoryIndex>=-nhmax && relativeHistoryIndex<=-1) {
00385 ClearLine();
00386 relativeHistoryIndex++;
00387
00388 if(relativeHistoryIndex==0) commandLine= commandLineBuf;
00389 else commandLine= RestoreHistory(currentHistoryNo+relativeHistoryIndex);
00390
00391 G4cout << commandLine << std::flush;
00392 cursorPosition= commandLine.length()+1;
00393 }
00394 }
00395
00396
00398 void G4UItcsh::ListMatchedCommand()
00400 {
00401 G4cout << G4endl;
00402
00403
00404 G4String input= G4String(commandLine).strip(G4String::leading);
00405
00406 G4int jhead= input.last(' ');
00407 if(jhead != G4int(G4String::npos)) {
00408 input.remove(0, jhead);
00409 input= input.strip(G4String::leading);
00410 }
00411
00412
00413
00414 G4String vpath = currentCommandDir;
00415 G4String vcmd = "";
00416
00417 if( !input.empty() ) {
00418 G4int len= input.length();
00419 G4int indx=-1;
00420 for(G4int i=len-1; i>=0; i--) {
00421 if(input[(size_t)i]=='/') {
00422 indx= i;
00423 break;
00424 }
00425 }
00426
00427 if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));
00428 if(!(indx==0 && len==1)) vcmd= input(indx+1,len-indx-1);
00429 }
00430
00431
00432
00433 ListCommand(vpath, vpath+vcmd);
00434
00435 G4cout << promptString << commandLine << std::flush;
00436 }
00437
00439 void G4UItcsh::CompleteCommand()
00441 {
00442
00443 G4String input= G4String(commandLine).strip(G4String::leading);
00444
00445 G4int jhead= input.last(' ');
00446 if(jhead != G4int(G4String::npos)) {
00447 input.remove(0, jhead);
00448 input= input.strip(G4String::leading);
00449 }
00450
00451
00452 size_t thead = input.find_last_of('/');
00453 G4String strtail = input;
00454 if (thead != G4String::npos) strtail = input(thead+1, input.size()-thead-1);
00455
00456
00457 G4String vpath= currentCommandDir;
00458 G4String vcmd;
00459
00460 G4int len= input.length();
00461 if(!input.empty()) {
00462 G4int indx= -1;
00463 for(G4int i=len-1; i>=0; i--) {
00464 if(input(i)=='/') {
00465 indx= i;
00466 break;
00467 }
00468 }
00469
00470 if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));
00471 if(!(indx==0 && len==1)) vcmd= input(indx+1,len-indx-1);
00472 }
00473
00474 G4UIcommandTree* atree= GetCommandTree(vpath);
00475 if(atree == NULL) return;
00476
00477
00478 G4String stream, strtmp;
00479 G4String inputpath= vpath+vcmd;
00480 G4int nMatch= 0;
00481
00482 int Ndir= atree-> GetTreeEntry();
00483 int Ncmd= atree-> GetCommandEntry();
00484
00485
00486 for(G4int idir=1; idir<=Ndir; idir++) {
00487 G4String fpdir= atree-> GetTree(idir)-> GetPathName();
00488
00489 if( fpdir.index(inputpath, 0) == 0) {
00490 if(nMatch==0) {
00491 stream= GetCommandPathTail(fpdir);
00492 } else {
00493 strtmp= GetCommandPathTail(fpdir);
00494 stream= GetFirstMatchedString(stream, strtmp);
00495 }
00496 nMatch++;
00497 }
00498 }
00499
00500
00501 for(G4int icmd=1; icmd<=Ncmd; icmd++){
00502 G4String fpcmd= atree-> GetPathName() +
00503 atree-> GetCommand(icmd) -> GetCommandName();
00504
00505 if( fpcmd.index(inputpath, 0) ==0) {
00506 if(nMatch==0) {
00507 stream= GetCommandPathTail(fpcmd) + " ";
00508 } else {
00509 strtmp= GetCommandPathTail(fpcmd) + " ";
00510 stream= GetFirstMatchedString(stream, strtmp);
00511 }
00512 nMatch++;
00513 }
00514 }
00515
00516
00517 input= commandLine;
00518
00519 jhead= input.last(' ');
00520 if(jhead == G4int(G4String::npos)) jhead=0;
00521 else jhead++;
00522
00523 G4int jt = jhead;
00524
00525 G4String dspstr;
00526 G4int i;
00527 for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS);
00528 for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(' ');
00529 for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS);
00530
00531 dspstr+= (vpath + stream);
00532 if (nMatch == 0) dspstr+= strtail;
00533 G4cout << dspstr << std::flush;
00534
00535
00536 input.remove(jt);
00537 input+= (vpath + stream);
00538 if (nMatch==0) input+= strtail;
00539
00540 commandLine= input;
00541 cursorPosition= commandLine.length()+1;
00542 }
00543
00544
00545
00546
00548 G4String G4UItcsh::ReadLine()
00550 {
00551 InitializeCommandLine();
00552
00553 char cc;
00554 do{
00555 G4cin.get(cc);
00556
00557
00558 switch(cc){
00559 case AsciiCtrA:
00560 MoveCursorTop();
00561 break;
00562 case AsciiCtrB:
00563 BackwardCursor();
00564 break;
00565 case AsciiCtrD:
00566 if(commandLine.length()!=0 && IsCursorLast()) ListMatchedCommand();
00567 else if (commandLine.empty()) {
00568 return G4String("exit");
00569 } else DeleteCharacter();
00570 break;
00571 case AsciiCtrE:
00572 MoveCursorEnd();
00573 break;
00574 case AsciiCtrF:
00575 ForwardCursor();
00576 break;
00577 case AsciiCtrK:
00578 ClearAfterCursor();
00579 break;
00580 case AsciiCtrL:
00581
00582 break;
00583 case AsciiCtrN:
00584 NextCommand();
00585 break;
00586 case AsciiCtrP:
00587 PreviousCommand();
00588 break;
00589 case AsciiTAB:
00590 if( (!commandLine.empty()) && IsCursorLast()) CompleteCommand();
00591 break;
00592 case AsciiDEL:
00593 BackspaceCharacter();
00594 break;
00595 case AsciiBS:
00596 BackspaceCharacter();
00597 break;
00598 case AsciiCtrC:
00599 break;
00600 case AsciiCtrQ:
00601 break;
00602 case AsciiCtrS:
00603 break;
00604 case AsciiCtrZ:
00605 break;
00606 default:
00607 break;
00608 }
00609
00610
00611 if( cc == AsciiESC) {
00612 G4cin.get(cc);
00613 if (cc == '[' || cc == 'O') {
00614 G4cin.get(cc);
00615 switch(cc) {
00616 case 'A':
00617 cc = 'P' - '@';
00618 PreviousCommand();
00619 break;
00620 case 'B':
00621 cc = 'N' - '@';
00622 NextCommand();
00623 break;
00624 case 'C':
00625 cc = 'F' - '@';
00626 ForwardCursor();
00627 break;
00628 case 'D':
00629 cc = 'B' - '@';
00630 BackwardCursor();
00631 break;
00632 default:
00633 cc = 0;
00634 break;
00635 }
00636 }
00637 }
00638
00639
00640 InsertCharacter(cc);
00641
00642 } while( cc != '\n');
00643
00644 return commandLine;
00645 }
00646
00648 G4String G4UItcsh::GetCommandLineString(const char* msg)
00650 {
00651 SetTermToInputMode();
00652
00653 MakePrompt(msg);
00654 relativeHistoryIndex= 0;
00655
00656 G4cout << promptString << std::flush;
00657
00658 G4String newCommand= ReadLine();
00659
00660 while( (newCommand.length() > 0) &&
00661 ( newCommand[newCommand.length()-1] == '_') ) {
00662 newCommand.remove(newCommand.length()-1);
00663 G4cout << G4endl;
00664 promptString= "? ";
00665 G4cout << promptString << std::flush;
00666 G4String newLine= ReadLine();
00667 newCommand.append(newLine);
00668 }
00669
00670
00671 G4bool isMeaningfull= FALSE;
00672 for (size_t i=0; i<newCommand.length(); i++) {
00673 if(newCommand[i] != ' ') {
00674 isMeaningfull= TRUE;
00675 break;
00676 }
00677 }
00678 if( !newCommand.empty() && isMeaningfull) StoreHistory(newCommand);
00679
00680
00681 RestoreTerm();
00682
00683 G4cout << G4endl;
00684 return newCommand;
00685 }
00686
00688 G4String G4UItcsh::GetFirstMatchedString(const G4String& str1,
00689 const G4String& str2) const
00691 {
00692 int nlen1= str1.length();
00693 int nlen2= str2.length();
00694
00695 int nmin = nlen1<nlen2 ? nlen1 : nlen2;
00696
00697 G4String strMatched;
00698 for(size_t i=0; G4int(i)<nmin; i++){
00699 if(str1[i]==str2[i]) {
00700 strMatched+= str1[i];
00701 } else {
00702 break;
00703 }
00704 }
00705
00706 return strMatched;
00707 }
00708
00709
00710
00711
00713 void G4UItcsh::StoreHistory(G4String aCommand)
00715 {
00716 G4int i= currentHistoryNo%maxHistory;
00717 if(i==0) i=maxHistory;
00718
00719 commandHistory[i-1]= aCommand;
00720 currentHistoryNo++;
00721 }
00722
00724 G4String G4UItcsh::RestoreHistory(G4int histNo)
00726 {
00727 if(histNo>= currentHistoryNo) return "";
00728
00729 G4int index= histNo%maxHistory;
00730 if(index==0) index= maxHistory;
00731
00732 return commandHistory[index-1];
00733 }
00734
00735
00736
00737
00739 void G4UItcsh::SetTermToInputMode()
00741 {
00742 termios tiosbuf= tios;
00743
00744 tiosbuf.c_iflag &= ~(BRKINT | ISTRIP);
00745 tiosbuf.c_iflag |= (IGNBRK | IGNPAR);
00746 tiosbuf.c_lflag &= ~(ICANON | IEXTEN | ECHO);
00747 tiosbuf.c_cc[VMIN] = 1;
00748 tiosbuf.c_cc[VTIME] = 0;
00749
00750 tcsetattr(0, TCSAFLUSH, &tiosbuf);
00751 }
00752
00753
00755 void G4UItcsh::RestoreTerm()
00757 {
00758 tcsetattr(0, TCSAFLUSH, &tios);
00759 }
00760
00761 #endif
00762