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
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
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
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':
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 '/':
00108 promptString.append(currentCommandDir);
00109 i++;
00110 break;
00111 case 'h':
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
00128 if(i == promptSetting.length()-1)
00129 promptString.append(G4String(promptSetting[i]));
00130 }
00131
00132
00133
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
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
00159 if(IsCursorLast()) {
00160 commandLine+= cc;
00161 } else {
00162 commandLine.insert(cursorPosition-1, G4String(cc));
00163 }
00164 cursorPosition++;
00165 }
00166
00168 void G4UItcsh::BackspaceCharacter()
00170 {
00171 if(cursorPosition==1) return;
00172
00173
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
00190 commandLine.erase(cursorPosition-2, 1);
00191
00192 cursorPosition--;
00193 }
00194
00196 void G4UItcsh::DeleteCharacter()
00198 {
00199 if(IsCursorLast()) return;
00200
00201
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
00213 commandLine.erase(cursorPosition-1, 1);
00214 }
00215
00217 void G4UItcsh::ClearLine()
00219 {
00220
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
00228 commandLine.erase();
00229 cursorPosition= 1;
00230 }
00231
00233 void G4UItcsh::ClearAfterCursor()
00235 {
00236 if(IsCursorLast()) return;
00237
00238
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
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
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
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
00352 G4String input= G4String(commandLine).strip(G4String::leading);
00353
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
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
00374 if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));
00375 if(!(indx==0 && len==1)) vcmd= input(indx+1,len-indx-1);
00376 }
00377
00378
00379 ListCommand(vpath, vpath+vcmd);
00380
00381 G4cout << promptString << commandLine << std::flush;
00382 }
00383
00385 void G4UItcsh::CompleteCommand()
00387 {
00388
00389 G4String input= G4String(commandLine).strip(G4String::leading);
00390
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
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
00411 if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));
00412 if(!(indx==0 && len==1)) vcmd= input(indx+1,len-indx-1);
00413 }
00414
00415 G4UIcommandTree* atree= GetCommandTree(vpath);
00416 if(atree == NULL) return;
00417
00418
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
00427 for(G4int idir=1; idir<=Ndir; idir++) {
00428 G4String fpdir= atree-> GetTree(idir)-> GetPathName();
00429
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
00442 for(G4int icmd=1; icmd<=Ncmd; icmd++){
00443 G4String fpcmd= atree-> GetPathName() +
00444 atree-> GetCommand(icmd) -> GetCommandName();
00445
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;
00458
00459
00460 input= commandLine;
00461
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);
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
00482 input.remove(jt);
00483 input+= stream;
00484
00485 commandLine= input;
00486 cursorPosition= commandLine.length()+1;
00487 }
00488
00489
00490
00491
00492
00494 G4String G4UItcsh::ReadLine()
00496 {
00497 InitializeCommandLine();
00498
00499 char cc;
00500 do{
00501 G4cin.get(cc);
00502
00503
00504 switch(cc){
00505 case AsciiCtrA:
00506 MoveCursorTop();
00507 break;
00508 case AsciiCtrB:
00509 BackwardCursor();
00510 break;
00511 case AsciiCtrD:
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:
00519 MoveCursorEnd();
00520 break;
00521 case AsciiCtrF:
00522 ForwardCursor();
00523 break;
00524 case AsciiCtrK:
00525 ClearAfterCursor();
00526 break;
00527 case AsciiCtrL:
00528
00529 break;
00530 case AsciiCtrN:
00531 NextCommand();
00532 break;
00533 case AsciiCtrP:
00534 PreviousCommand();
00535 break;
00536 case AsciiTAB:
00537 if( (!commandLine.empty()) && IsCursorLast()) CompleteCommand();
00538 break;
00539 case AsciiDEL:
00540 BackspaceCharacter();
00541 break;
00542 case AsciiBS:
00543 BackspaceCharacter();
00544 break;
00545 case AsciiCtrC:
00546 break;
00547 case AsciiCtrQ:
00548 break;
00549 case AsciiCtrS:
00550 break;
00551 case AsciiCtrZ:
00552 break;
00553 default:
00554 break;
00555 }
00556
00557
00558 if( cc == AsciiESC) {
00559 G4cin.get(cc);
00560 if (cc == '[' || 'O') {
00561 G4cin.get(cc);
00562 switch(cc) {
00563 case 'A':
00564 cc = 'P' - '@';
00565 PreviousCommand();
00566 break;
00567 case 'B':
00568 cc = 'N' - '@';
00569 NextCommand();
00570 break;
00571 case 'C':
00572 cc = 'F' - '@';
00573 ForwardCursor();
00574 break;
00575 case 'D':
00576 cc = 'B' - '@';
00577 BackwardCursor();
00578 break;
00579 default:
00580 cc = 0;
00581 break;
00582 }
00583 }
00584 }
00585
00586
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);
00601 relativeHistoryIndex= 0;
00602
00603 G4cout << promptString << std::flush;
00604
00605 G4String newCommand= ReadLine();
00606
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
00618 G4bool isMeaningfull= FALSE;
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
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
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;
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];
00680 }
00681
00682
00683
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