source: trunk/geant4/interfaces/basic/src/G4UItcsh.cc @ 483

Last change on this file since 483 was 483, checked in by garnier, 17 years ago

r569@mac-90108: laurentgarnier | 2007-06-05 15:53:34 +0200
version contre geant4.8.2.p01

File size: 18.4 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.12 2006/06/29 19:09:54 gunter Exp $
28// GEANT4 tag $Name: geant4-08-01-patch-01 $
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
40// ASCII character code
41static const char AsciiCtrA = '\001';
42static const char AsciiCtrB = '\002';
43static const char AsciiCtrC = '\003';
44static const char AsciiCtrD = '\004';
45static const char AsciiCtrE = '\005';
46static const char AsciiCtrF = '\006';
47static const char AsciiCtrK = '\013';
48static const char AsciiCtrL = '\014';
49static const char AsciiCtrN = '\016';
50static const char AsciiCtrP = '\020';
51static const char AsciiCtrQ = '\021';
52static const char AsciiCtrS = '\023';
53static const char AsciiCtrZ = '\032';
54static const char AsciiTAB   = '\011';
55static const char AsciiBS    = '\010';
56static const char AsciiDEL   = '\177';
57static const char AsciiESC   = '\033';
58
59static const int AsciiPrintableMin = 32;
60
61/////////////////////////////////////////////////////////
62G4UItcsh::G4UItcsh(const G4String& prompt, G4int maxhist)
63  : G4VUIshell(prompt),
64    commandLine(""), cursorPosition(1),
65    commandHistory(maxhist), maxHistory(maxhist),
66    currentHistoryNo(1), relativeHistoryIndex(0)
67/////////////////////////////////////////////////////////
68{ 
69  // get current terminal mode
70  tcgetattr(0, &tios);
71}
72
73/////////////////////
74G4UItcsh::~G4UItcsh()
75/////////////////////
76{
77}
78 
79///////////////////////////
80void G4UItcsh::MakePrompt(const char* msg)
81///////////////////////////
82{
83  if(promptSetting.length()<=1) {
84    promptString= promptSetting;
85    return;
86  }
87
88  promptString="";
89  size_t i;
90  for(i=0; i<promptSetting.length()-1; i++){
91    if(promptSetting[i]=='%'){
92      switch (promptSetting[i+1]) {
93      case 's':  // current application status
94        {
95          G4String stateStr;
96          if(msg)
97          { stateStr = msg; }
98          else
99          {
100            G4StateManager* statM= G4StateManager::GetStateManager();
101            stateStr= statM-> GetStateString(statM->GetCurrentState());
102          }
103          promptString.append(stateStr);
104          i++;
105        }
106        break;
107      case '/':  // current working directory
108        promptString.append(currentCommandDir);
109        i++;
110        break;
111      case 'h':  // history#
112        {
113        std::ostringstream os;
114        os << currentHistoryNo;
115        promptString.append(os.str());
116        i++;
117        }
118        break;
119      default:
120        break;
121      } 
122    } else {
123      promptString.append(G4String(promptSetting[i]));
124    }
125  }
126
127  // append last chaacter
128  if(i == promptSetting.length()-1) 
129    promptString.append(G4String(promptSetting[i]));
130}
131
132// --------------------------------------------------------------------
133//      commad line operations
134// --------------------------------------------------------------------
135//////////////////////////////////////
136void G4UItcsh::InitializeCommandLine()
137//////////////////////////////////////
138{
139  commandLine= "";
140  cursorPosition= 1;
141}
142
143///////////////////////////////////////
144void G4UItcsh::InsertCharacter(char cc)
145///////////////////////////////////////
146{
147  if( ! (cc >= AsciiPrintableMin  && isprint(cc)) ) return;
148
149  // display...
150  G4cout << cc;
151  size_t i;
152  for(i=cursorPosition-1; i<commandLine.length() ;i++) 
153    G4cout << commandLine[i];
154  for(i=cursorPosition-1; i<commandLine.length() ;i++)
155    G4cout << AsciiBS;
156  G4cout << std::flush;
157   
158  // command line string...
159  if(IsCursorLast()) {  // add
160    commandLine+= cc;
161  } else { // insert
162    commandLine.insert(cursorPosition-1, G4String(cc));
163  }
164  cursorPosition++;
165}
166 
167///////////////////////////////////
168void G4UItcsh::BackspaceCharacter()
169///////////////////////////////////
170{
171  if(cursorPosition==1) return;
172
173  // display...
174  if(IsCursorLast()) { 
175    G4cout << AsciiBS << ' ' << AsciiBS << std::flush;
176  } else { 
177    G4cout << AsciiBS;
178    size_t i;
179    for(i=cursorPosition-2; i< commandLine.length()-1 ;i++){
180      G4cout << commandLine[i+1];
181    }
182    G4cout << ' ';
183    for(i=cursorPosition-2; i< commandLine.length() ;i++){
184      G4cout << AsciiBS;
185    }
186    G4cout << std::flush;
187  }
188
189  // command line string...
190  commandLine.erase(cursorPosition-2, 1);
191
192  cursorPosition--;
193}
194
195////////////////////////////////
196void G4UItcsh::DeleteCharacter()
197////////////////////////////////
198{
199  if(IsCursorLast()) return;
200
201  // display...
202  size_t i;
203  for(i=cursorPosition-1; i< commandLine.length()-1 ;i++){
204    G4cout << commandLine[i+1];
205  }
206  G4cout << ' ';
207  for(i=cursorPosition-1; i< commandLine.length() ;i++){
208    G4cout << AsciiBS;
209  }
210  G4cout << std::flush;
211
212  // command lin string...
213  commandLine.erase(cursorPosition-1, 1);
214}
215
216//////////////////////////
217void G4UItcsh::ClearLine()
218//////////////////////////
219{
220  // display...
221  G4int i;
222  for(i= cursorPosition; i>=2; i--) G4cout << AsciiBS;
223  for(i=1; i<=G4int(commandLine.length()); i++) G4cout << ' ';
224  for(i=1; i<=G4int(commandLine.length()); i++) G4cout << AsciiBS;
225  G4cout << std::flush;
226 
227  // command line string...
228  commandLine.erase();
229  cursorPosition= 1;
230}
231
232/////////////////////////////////
233void G4UItcsh::ClearAfterCursor()
234/////////////////////////////////
235{
236  if(IsCursorLast()) return;
237
238  // display...
239  G4int i;
240  for(i=cursorPosition; i<=G4int(commandLine.length()); i++) G4cout << ' ';
241  for(i=commandLine.length(); i>=cursorPosition; i--) G4cout << AsciiBS;
242  G4cout << std::flush;
243
244  // command line string...
245  commandLine.erase(cursorPosition-1, 
246                    commandLine.length()-cursorPosition+1);
247}
248
249////////////////////////////
250void G4UItcsh::ClearScreen()
251////////////////////////////
252{
253  if(! clearString.empty() ) {
254    G4cout << clearString;
255
256    G4cout << promptString << commandLine << std::flush;
257    // reset cursur position
258    for(G4int i=commandLine.length()+1; i>=cursorPosition+1; i--) 
259      G4cout << AsciiBS << std::flush;
260  }
261}
262
263//////////////////////////////
264void G4UItcsh::ForwardCursor()
265//////////////////////////////
266{
267  if(IsCursorLast()) return;
268
269  G4cout << commandLine[(size_t)(cursorPosition-1)] << std::flush;
270  cursorPosition++;
271}
272
273///////////////////////////////
274void G4UItcsh::BackwardCursor()
275///////////////////////////////
276{
277  if(cursorPosition==1) return;
278
279  cursorPosition--;
280  G4cout << AsciiBS << std::flush;
281}
282
283//////////////////////////////
284void G4UItcsh::MoveCursorTop()
285//////////////////////////////
286{
287  for(G4int i=cursorPosition; i>1; i--){
288    G4cout << AsciiBS;
289  }
290  G4cout << std::flush;
291  cursorPosition=1;
292}
293
294//////////////////////////////
295void G4UItcsh::MoveCursorEnd()
296//////////////////////////////
297{
298  for(size_t i=cursorPosition-1; i<commandLine.length(); i++){
299    G4cout << commandLine[i];
300  }
301  G4cout << std::flush;
302  cursorPosition=commandLine.length()+1;
303}
304
305////////////////////////////////
306void G4UItcsh::PreviousCommand()
307////////////////////////////////
308{
309  G4int nhmax= currentHistoryNo-1 >= maxHistory ? 
310                 maxHistory : currentHistoryNo-1;
311
312  // retain current input
313  if(relativeHistoryIndex==0) commandLineBuf= commandLine;
314
315  if(relativeHistoryIndex>=-nhmax+1 && relativeHistoryIndex<=0) {
316    ClearLine();
317    relativeHistoryIndex--;
318    commandLine= RestoreHistory(currentHistoryNo+relativeHistoryIndex);
319
320    G4cout << commandLine << std::flush;
321    cursorPosition= commandLine.length()+1;
322  }
323}
324
325////////////////////////////
326void G4UItcsh::NextCommand()
327////////////////////////////
328{ 
329  G4int nhmax= currentHistoryNo-1 >= maxHistory ? 
330                 maxHistory : currentHistoryNo-1;
331
332  if(relativeHistoryIndex>=-nhmax && relativeHistoryIndex<=-1) {
333    ClearLine();
334    relativeHistoryIndex++;
335
336    if(relativeHistoryIndex==0) commandLine= commandLineBuf;
337    else commandLine= RestoreHistory(currentHistoryNo+relativeHistoryIndex);
338
339    G4cout << commandLine << std::flush;     
340    cursorPosition= commandLine.length()+1;
341  }
342}
343
344
345///////////////////////////////////
346void G4UItcsh::ListMatchedCommand()
347///////////////////////////////////
348{
349  G4cout << G4endl;
350 
351  // input string
352  G4String input= G4String(commandLine).strip(G4String::leading);
353  // target token is last token
354  G4int jhead= input.last(' ');
355  if(jhead != G4int(G4String::npos)) {
356    input.remove(0, jhead);
357    input= input.strip(G4String::leading);
358  }
359
360  // command tree of "user specified directory"
361  G4String vpath= currentCommandDir;
362  G4String vcmd;
363
364  if( !input.empty() ) {
365    G4int len= input.length();
366    G4int indx=-1;
367    for(G4int i=len-1; i>=0; i--) {
368      if(input[(size_t)i]=='/') {
369        indx= i;
370        break;
371      }   
372    }
373    // get abs. path
374    if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1)); 
375    if(!(indx==0  && len==1)) vcmd= input(indx+1,len-indx-1);  // care for "/"
376  }
377
378  // list matched dirs/commands
379  ListCommand(vpath, vpath+vcmd);
380
381  G4cout << promptString << commandLine << std::flush;
382}
383
384////////////////////////////////
385void G4UItcsh::CompleteCommand()
386////////////////////////////////
387{
388  // inputting string
389  G4String input= G4String(commandLine).strip(G4String::leading);
390  // target token is last token
391  G4int jhead= input.last(' ');
392  if(jhead != G4int(G4String::npos)) {
393    input.remove(0, jhead);
394    input= input.strip(G4String::leading);
395  }
396
397  // command tree of "user specified directory" 
398  G4String vpath= currentCommandDir;
399  G4String vcmd;
400
401  G4int len= input.length();
402  if(!input.empty()) {
403    G4int indx= -1;
404    for(G4int i=len-1; i>=0; i--) {
405      if(input(i)=='/') {
406        indx= i;
407        break;
408      }   
409    }
410    // get abs. path
411    if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1)); 
412    if(!(indx==0  && len==1)) vcmd= input(indx+1,len-indx-1);  // care for "/"
413  }
414
415  G4UIcommandTree* atree= GetCommandTree(vpath);  // get command tree
416  if(atree == NULL) return;
417
418  // list matched directories/commands
419  G4String stream, strtmp;
420  G4String inputpath= vpath+vcmd;
421  G4int nMatch= 0;
422
423  int Ndir= atree-> GetTreeEntry();
424  int Ncmd= atree-> GetCommandEntry();
425 
426  // directory ...
427  for(G4int idir=1; idir<=Ndir; idir++) {
428    G4String fpdir= atree-> GetTree(idir)-> GetPathName();
429    // matching test
430    if( fpdir.index(inputpath, 0) == 0) {
431      if(nMatch==0) {
432        stream= GetCommandPathTail(fpdir);
433      } else {
434        strtmp= GetCommandPathTail(fpdir);
435        stream= GetFirstMatchedString(stream, strtmp);
436      }
437      nMatch++;
438    }
439  }
440 
441  // command ...
442  for(G4int icmd=1; icmd<=Ncmd; icmd++){
443    G4String fpcmd= atree-> GetPathName() +
444                    atree-> GetCommand(icmd) -> GetCommandName();
445    // matching test
446    if( fpcmd.index(inputpath, 0) ==0) {
447      if(nMatch==0) {
448        stream= GetCommandPathTail(fpcmd) + " ";
449      } else {
450        strtmp= GetCommandPathTail(fpcmd) + " ";
451        stream= GetFirstMatchedString(stream, strtmp);
452      }
453      nMatch++;
454    }
455  }
456
457  if(nMatch==0) return;  // no matched
458
459  // display...
460  input= commandLine;
461  // target token is last token
462  jhead= input.last(' ');
463  if(jhead == G4int(G4String::npos)) jhead=0;
464  else jhead++;
465
466  G4int jt= input.find_last_of('/');
467  if(jt<jhead) jt=G4String::npos;
468
469  if(jt==G4int(G4String::npos)) jt= jhead;
470  else jt++;
471
472  G4String dspstr; 
473  G4int i;
474  for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS); // cleanup
475  for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(' '); 
476  for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS); 
477
478  dspstr+= stream;
479  G4cout << dspstr << std::flush; 
480
481  // command line string
482  input.remove(jt);
483  input+= stream;
484
485  commandLine= input;
486  cursorPosition= commandLine.length()+1;
487}
488
489
490// --------------------------------------------------------------------
491//      commad line
492// --------------------------------------------------------------------
493/////////////////////////////
494G4String G4UItcsh::ReadLine()
495/////////////////////////////
496{
497  InitializeCommandLine();
498
499  char cc;
500  do{  // input loop
501    G4cin.get(cc);
502
503    // treatment for special character
504    switch(cc){
505    case AsciiCtrA:       // ... move cursor to the top
506      MoveCursorTop();
507      break;
508    case AsciiCtrB:       // ... backward cursor
509      BackwardCursor();
510      break;
511    case AsciiCtrD:       // ... delete/exit/show matched list
512      if(commandLine.length()!=0 && IsCursorLast()) ListMatchedCommand();
513      else if (commandLine.empty()) {
514        G4cout << G4endl;
515        exit(0);
516      } else DeleteCharacter();
517      break;
518    case AsciiCtrE:       // ... move cursor to the end
519      MoveCursorEnd();
520      break;
521    case AsciiCtrF:       // ... forward cursor
522      ForwardCursor();
523      break;
524    case AsciiCtrK:       // ... clear after the cursor
525      ClearAfterCursor();
526      break;
527    case AsciiCtrL:       // ... clear screen
528      // ClearScreen();
529      break;
530    case AsciiCtrN:     // ... next command
531      NextCommand();
532      break;
533    case AsciiCtrP:     // ... previous command
534      PreviousCommand();
535      break;
536    case AsciiTAB:         // ... command completion
537      if( (!commandLine.empty()) && IsCursorLast()) CompleteCommand();
538      break;
539    case AsciiDEL:         // ... backspace
540      BackspaceCharacter();
541      break;
542    case AsciiBS:          // ... backspace
543      BackspaceCharacter();
544      break;
545    case AsciiCtrC:       // ... kill prompt
546      break;
547    case AsciiCtrQ:       // ... restarts suspeded output
548      break;
549    case AsciiCtrS:       // ... suspend output
550      break;
551    case AsciiCtrZ:       // ... suspend
552      break;
553    default:
554      break;
555    }
556
557    // treatment for ESC. character
558    if( cc == AsciiESC) { // ESC
559      G4cin.get(cc);
560      if (cc == '[' || 'O') { // care for another termcap, such as konsole
561        G4cin.get(cc);
562        switch(cc) {
563        case 'A': // [UP]
564          cc = 'P' - '@';
565          PreviousCommand();  // ... show previous commad
566          break;
567        case 'B': // [DOWN]
568          cc = 'N' - '@';
569          NextCommand();  // ... show next commad
570          break;
571        case 'C': // [RIGHT]
572          cc = 'F' - '@';
573          ForwardCursor();   // ... forward cursor
574          break;
575        case 'D': // [LEFT]
576          cc = 'B' - '@';
577          BackwardCursor();      // ... backward cursor
578          break;
579        default:  // who knows !?
580          cc = 0;
581          break;
582        }
583      }
584    }
585
586    // insert character to command line and display
587    InsertCharacter(cc);
588 
589  } while( cc != '\n');
590
591  return commandLine;
592}
593
594///////////////////////////////////
595G4String G4UItcsh::GetCommandLine(const char* msg)
596///////////////////////////////////
597{
598  SetTermToInputMode();
599
600  MakePrompt(msg); // update
601  relativeHistoryIndex= 0;
602
603  G4cout << promptString << std::flush;
604
605  G4String newCommand= ReadLine();  // read line...
606  // multi-line
607  while( (newCommand.length() > 0) &&
608         ( newCommand[newCommand.length()-1] == '_') ) {
609    newCommand.remove(newCommand.length()-1);
610    G4cout << G4endl;
611    promptString= "? ";
612    G4cout << promptString << std::flush;
613    G4String newLine= ReadLine();
614    newCommand.append(newLine);
615  }
616
617  // update history...
618  G4bool isMeaningfull= FALSE; // check NULL command
619  for (size_t i=0; i<newCommand.length(); i++) {
620    if(newCommand[i] != ' ') {
621      isMeaningfull= TRUE;
622      break;
623    }
624  }
625  if( !newCommand.empty() && isMeaningfull) StoreHistory(newCommand);
626
627  // reset terminal
628  RestoreTerm();
629
630  G4cout << G4endl;
631  return newCommand;
632}
633
634////////////////////////////////////////////////////////////////////
635G4String G4UItcsh::GetFirstMatchedString(const G4String& str1, 
636                                         const G4String& str2) const
637////////////////////////////////////////////////////////////////////
638{
639  int nlen1= str1.length();
640  int nlen2= str2.length();
641
642  int nmin = nlen1<nlen2 ? nlen1 : nlen2;
643
644  G4String strMatched;
645  for(size_t i=0; G4int(i)<nmin; i++){
646    if(str1[i]==str2[i]) {
647      strMatched+= str1[i];
648    } else {
649      break;
650    }
651  }
652
653  return strMatched;
654}
655
656// --------------------------------------------------------------------
657//      history
658// --------------------------------------------------------------------
659//////////////////////////////////////////////
660void G4UItcsh::StoreHistory(G4String aCommand)
661//////////////////////////////////////////////
662{
663  G4int i= currentHistoryNo%maxHistory; 
664  if(i==0) i=maxHistory;
665
666  commandHistory[i-1]= aCommand;  // 0-offset
667  currentHistoryNo++;
668}
669
670///////////////////////////////////////////////
671G4String G4UItcsh::RestoreHistory(G4int histNo)
672///////////////////////////////////////////////
673{
674  if(histNo>= currentHistoryNo) return "";
675
676  G4int index= histNo%maxHistory;
677  if(index==0) index= maxHistory;
678
679  return commandHistory[index-1]; // 0-offset
680}
681
682// --------------------------------------------------------------------
683//      terminal mode
684// --------------------------------------------------------------------
685///////////////////////////////////
686void G4UItcsh::SetTermToInputMode()
687///////////////////////////////////
688{ 
689  termios tiosbuf= tios;
690
691  tiosbuf.c_iflag &= ~(BRKINT | ISTRIP);
692  tiosbuf.c_iflag |= (IGNBRK | IGNPAR);
693  tiosbuf.c_lflag &= ~(ICANON | IEXTEN | ECHO);
694  tiosbuf.c_cc[VMIN] = 1;
695  tiosbuf.c_cc[VTIME] = 0;
696 
697  tcsetattr(0, TCSAFLUSH, &tiosbuf);
698}
699
700
701////////////////////////////
702void G4UItcsh::RestoreTerm()
703////////////////////////////
704{
705  tcsetattr(0, TCSAFLUSH, &tios);
706} 
707
708#endif
709
Note: See TracBrowser for help on using the repository browser.