ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4UItcsh.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4UItcsh.cc
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 //
28 
29 #ifndef WIN32
30 
31 #include "G4Types.hh"
32 #include "G4StateManager.hh"
33 #include "G4UIcommandStatus.hh"
34 #include "G4UItcsh.hh"
35 #include <ctype.h>
36 #include <sstream>
37 #include <fstream>
38 #include <stdlib.h>
39 
40 // ASCII character code
41 static const char AsciiCtrA = '\001';
42 static const char AsciiCtrB = '\002';
43 static const char AsciiCtrC = '\003';
44 static const char AsciiCtrD = '\004';
45 static const char AsciiCtrE = '\005';
46 static const char AsciiCtrF = '\006';
47 static const char AsciiCtrK = '\013';
48 static const char AsciiCtrL = '\014';
49 static const char AsciiCtrN = '\016';
50 static const char AsciiCtrP = '\020';
51 static const char AsciiCtrQ = '\021';
52 static const char AsciiCtrS = '\023';
53 static const char AsciiCtrZ = '\032';
54 static const char AsciiTAB = '\011';
55 static const char AsciiBS = '\010';
56 static const char AsciiDEL = '\177';
57 static const char AsciiESC = '\033';
58 
59 static const int AsciiPrintableMin = 32;
60 
61 // history file
62 static const G4String historyFileName= "/.g4_hist";
63 
65 G4UItcsh::G4UItcsh(const G4String& prompt, G4int maxhist)
66  : G4VUIshell(prompt),
67  commandLine(""), cursorPosition(1),
68  commandHistory(maxhist), maxHistory(maxhist),
69  currentHistoryNo(1), relativeHistoryIndex(0)
71 {
72  // get current terminal mode
73  tcgetattr(0, &tios);
74 
75  // read a shell history file
76  const char* path = std::getenv("HOME");
77  if( path == NULL ) return;
78 
79  G4String homedir= path;
80  G4String fname= homedir + historyFileName;
81 
82  std::ifstream histfile;
83  enum { BUFSIZE= 1024 }; char linebuf[BUFSIZE];
84 
85  histfile.open(fname, std::ios::in);
86  while (histfile.good()) {
87  if(histfile.eof()) break;
88 
89  histfile.getline(linebuf, BUFSIZE);
90  G4String aline= linebuf;
91  aline.strip(G4String::both);
92  if(aline.size() != 0) StoreHistory(linebuf);
93  }
94  histfile.close();
95 }
96 
100 {
101  // store a shell history
102  const char* path = std::getenv("HOME");
103  if( path == NULL ) return;
104 
105  G4String homedir= path;
106  G4String fname= homedir + historyFileName;
107 
108  std::ofstream histfile;
109  histfile.open(fname, std::ios::out);
110 
111  G4int n0hist= 1;
113 
114  for (G4int i=n0hist; i<= currentHistoryNo; i++) {
115  histfile << RestoreHistory(i) << G4endl;
116  }
117 
118  histfile.close();
119 }
120 
122 void G4UItcsh::MakePrompt(const char* msg)
124 {
125  if(promptSetting.length()<=1) {
127  return;
128  }
129 
130  promptString="";
131  size_t i;
132  for(i=0; i<promptSetting.length()-1; i++){
133  if(promptSetting[i]=='%'){
134  switch (promptSetting[i+1]) {
135  case 's': // current application status
136  {
137  G4String stateStr;
138  if(msg)
139  { stateStr = msg; }
140  else
141  {
143  stateStr= statM-> GetStateString(statM->GetCurrentState());
144  }
145  promptString.append(stateStr);
146  i++;
147  }
148  break;
149  case '/': // current working directory
151  i++;
152  break;
153  case 'h': // history#
154  {
155  std::ostringstream os;
156  os << currentHistoryNo;
157  promptString.append(os.str());
158  i++;
159  }
160  break;
161  default:
162  break;
163  }
164  } else {
166  }
167  }
168 
169  // append last chaacter
170  if(i == promptSetting.length()-1)
172 }
173 
174 
178 {
179  RestoreTerm();
180 }
181 
182 
183 // --------------------------------------------------------------------
184 // commad line operations
185 // --------------------------------------------------------------------
189 {
190  commandLine= "";
191  cursorPosition= 1;
192 }
193 
197 {
198  if( ! (cc >= AsciiPrintableMin && isprint(cc)) ) return;
199 
200  // display...
201  G4cout << cc;
202  size_t i;
203  for(i=cursorPosition-1; i<commandLine.length() ;i++)
204  G4cout << commandLine[i];
205  for(i=cursorPosition-1; i<commandLine.length() ;i++)
206  G4cout << AsciiBS;
207  G4cout << std::flush;
208 
209  // command line string...
210  if(IsCursorLast()) { // add
211  commandLine+= cc;
212  } else { // insert
213  commandLine.insert(cursorPosition-1, G4String(cc));
214  }
215  cursorPosition++;
216 }
217 
221 {
222  if(cursorPosition==1) return;
223 
224  // display...
225  if(IsCursorLast()) {
226  G4cout << AsciiBS << ' ' << AsciiBS << std::flush;
227  } else {
228  G4cout << AsciiBS;
229  size_t i;
230  for(i=cursorPosition-2; i< commandLine.length()-1 ;i++){
231  G4cout << commandLine[i+1];
232  }
233  G4cout << ' ';
234  for(i=cursorPosition-2; i< commandLine.length() ;i++){
235  G4cout << AsciiBS;
236  }
237  G4cout << std::flush;
238  }
239 
240  // command line string...
241  commandLine.erase(cursorPosition-2, 1);
242 
243  cursorPosition--;
244 }
245 
249 {
250  if(IsCursorLast()) return;
251 
252  // display...
253  size_t i;
254  for(i=cursorPosition-1; i< commandLine.length()-1 ;i++){
255  G4cout << commandLine[i+1];
256  }
257  G4cout << ' ';
258  for(i=cursorPosition-1; i< commandLine.length() ;i++){
259  G4cout << AsciiBS;
260  }
261  G4cout << std::flush;
262 
263  // command lin string...
264  commandLine.erase(cursorPosition-1, 1);
265 }
266 
270 {
271  // display...
272  G4int i;
273  for(i= cursorPosition; i>=2; i--) G4cout << AsciiBS;
274  for(i=1; i<=G4int(commandLine.length()); i++) G4cout << ' ';
275  for(i=1; i<=G4int(commandLine.length()); i++) G4cout << AsciiBS;
276  G4cout << std::flush;
277 
278  // command line string...
279  commandLine.erase();
280  cursorPosition= 1;
281 }
282 
286 {
287  if(IsCursorLast()) return;
288 
289  // display...
290  G4int i;
291  for(i=cursorPosition; i<=G4int(commandLine.length()); i++) G4cout << ' ';
292  for(i=commandLine.length(); i>=cursorPosition; i--) G4cout << AsciiBS;
293  G4cout << std::flush;
294 
295  // command line string...
296  commandLine.erase(cursorPosition-1,
297  commandLine.length()-cursorPosition+1);
298 }
299 
303 {
304  if(! clearString.empty() ) {
305  G4cout << clearString;
306 
307  G4cout << promptString << commandLine << std::flush;
308  // reset cursur position
309  for(G4int i=commandLine.length()+1; i>=cursorPosition+1; i--)
310  G4cout << AsciiBS << std::flush;
311  }
312 }
313 
317 {
318  if(IsCursorLast()) return;
319 
320  G4cout << commandLine[(size_t)(cursorPosition-1)] << std::flush;
321  cursorPosition++;
322 }
323 
327 {
328  if(cursorPosition==1) return;
329 
330  cursorPosition--;
331  G4cout << AsciiBS << std::flush;
332 }
333 
337 {
338  for(G4int i=cursorPosition; i>1; i--){
339  G4cout << AsciiBS;
340  }
341  G4cout << std::flush;
342  cursorPosition=1;
343 }
344 
348 {
349  for(size_t i=cursorPosition-1; i<commandLine.length(); i++){
350  G4cout << commandLine[i];
351  }
352  G4cout << std::flush;
353  cursorPosition=commandLine.length()+1;
354 }
355 
359 {
360  G4int nhmax= currentHistoryNo-1 >= maxHistory ?
362 
363  // retain current input
365 
366  if(relativeHistoryIndex>=-nhmax+1 && relativeHistoryIndex<=0) {
367  ClearLine();
370 
371  G4cout << commandLine << std::flush;
372  cursorPosition= commandLine.length()+1;
373  }
374 }
375 
379 {
380  G4int nhmax= currentHistoryNo-1 >= maxHistory ?
382 
383  if(relativeHistoryIndex>=-nhmax && relativeHistoryIndex<=-1) {
384  ClearLine();
386 
389 
390  G4cout << commandLine << std::flush;
391  cursorPosition= commandLine.length()+1;
392  }
393 }
394 
395 
399 {
400  G4cout << G4endl;
401 
402  // input string
404  // target token is last token
405  G4int jhead= input.last(' ');
406  if(jhead != G4int(G4String::npos)) {
407  input.remove(0, jhead);
408  input= input.strip(G4String::leading);
409  }
410  //G4cout << "@@@@ input=" << input << G4endl;
411 
412  // command tree of "user specified directory"
413  G4String vpath = currentCommandDir;
414  G4String vcmd = "";
415 
416  if( !input.empty() ) {
417  G4int len= input.length();
418  G4int indx=-1;
419  for(G4int i=len-1; i>=0; i--) {
420  if(input[(size_t)i]=='/') {
421  indx= i;
422  break;
423  }
424  }
425  // get abs. path
426  if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));
427  if(!(indx==0 && len==1)) vcmd= input(indx+1,len-indx-1); // care for "/"
428  }
429 
430  // list matched dirs/commands
431  //G4cout << "@@@ vpath=" << vpath <<":vcmd=" << vcmd << G4endl;
432  ListCommand(vpath, vpath+vcmd);
433 
434  G4cout << promptString << commandLine << std::flush;
435 }
436 
440 {
441  // inputting string
443  // target token is last token
444  G4int jhead= input.last(' ');
445  if(jhead != G4int(G4String::npos)) {
446  input.remove(0, jhead);
447  input= input.strip(G4String::leading);
448  }
449 
450  // tail string
451  size_t thead = input.find_last_of('/');
452  G4String strtail = input;
453  if (thead != G4String::npos) strtail = input(thead+1, input.size()-thead-1);
454 
455  // command tree of "user specified directory"
457  G4String vcmd;
458 
459  G4int len= input.length();
460  if(!input.empty()) {
461  G4int indx= -1;
462  for(G4int i=len-1; i>=0; i--) {
463  if(input(i)=='/') {
464  indx= i;
465  break;
466  }
467  }
468  // get abs. path
469  if(indx != -1) vpath= GetAbsCommandDirPath(input(0,indx+1));
470  if(!(indx==0 && len==1)) vcmd= input(indx+1,len-indx-1); // care for "/"
471  }
472 
473  G4UIcommandTree* atree= GetCommandTree(vpath); // get command tree
474  if(atree == NULL) return;
475 
476  // list matched directories/commands
477  G4String stream, strtmp;
478  G4String inputpath= vpath+vcmd;
479  G4int nMatch= 0;
480 
481  int Ndir= atree-> GetTreeEntry();
482  int Ncmd= atree-> GetCommandEntry();
483 
484  // directory ...
485  for(G4int idir=1; idir<=Ndir; idir++) {
486  G4String fpdir= atree-> GetTree(idir)-> GetPathName();
487  // matching test
488  if( fpdir.index(inputpath, 0) == 0) {
489  if(nMatch==0) {
490  stream= GetCommandPathTail(fpdir);
491  } else {
492  strtmp= GetCommandPathTail(fpdir);
493  stream= GetFirstMatchedString(stream, strtmp);
494  }
495  nMatch++;
496  }
497  }
498 
499  // command ...
500  for(G4int icmd=1; icmd<=Ncmd; icmd++){
501  G4String fpcmd= atree-> GetPathName() +
502  atree-> GetCommand(icmd) -> GetCommandName();
503  // matching test
504  if( fpcmd.index(inputpath, 0) ==0) {
505  if(nMatch==0) {
506  stream= GetCommandPathTail(fpcmd) + " ";
507  } else {
508  strtmp= GetCommandPathTail(fpcmd) + " ";
509  stream= GetFirstMatchedString(stream, strtmp);
510  }
511  nMatch++;
512  }
513  }
514 
515  // display...
516  input= commandLine;
517  // target token is last token
518  jhead= input.last(' ');
519  if(jhead == G4int(G4String::npos)) jhead=0;
520  else jhead++;
521 
522  G4int jt = jhead;
523 
524  G4String dspstr;
525  G4int i;
526  for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS);
527  for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(' ');
528  for(i=jt; i<=G4int(input.length())-1; i++) dspstr+= G4String(AsciiBS);
529 
530  dspstr+= (vpath + stream);
531  if (nMatch == 0) dspstr+= strtail;
532  G4cout << dspstr << std::flush;
533 
534  // command line string
535  input.remove(jt);
536  input+= (vpath + stream);
537  if (nMatch==0) input+= strtail;
538 
539  commandLine= input;
540  cursorPosition= commandLine.length()+1;
541 }
542 
543 // --------------------------------------------------------------------
544 // commad line
545 // --------------------------------------------------------------------
549 {
551 
552  char cc;
553  do{ // input loop
554  G4cin.get(cc);
555 
556  // treatment for special character
557  switch(cc){
558  case AsciiCtrA: // ... move cursor to the top
559  MoveCursorTop();
560  break;
561  case AsciiCtrB: // ... backward cursor
562  BackwardCursor();
563  break;
564  case AsciiCtrD: // ... delete/exit/show matched list
565  if(commandLine.length()!=0 && IsCursorLast()) ListMatchedCommand();
566  else if (commandLine.empty()) {
567  return G4String("exit");
568  } else DeleteCharacter();
569  break;
570  case AsciiCtrE: // ... move cursor to the end
571  MoveCursorEnd();
572  break;
573  case AsciiCtrF: // ... forward cursor
574  ForwardCursor();
575  break;
576  case AsciiCtrK: // ... clear after the cursor
578  break;
579  case AsciiCtrL: // ... clear screen
580  // ClearScreen();
581  break;
582  case AsciiCtrN: // ... next command
583  NextCommand();
584  break;
585  case AsciiCtrP: // ... previous command
586  PreviousCommand();
587  break;
588  case AsciiTAB: // ... command completion
589  if( (!commandLine.empty()) && IsCursorLast()) CompleteCommand();
590  break;
591  case AsciiDEL: // ... backspace
593  break;
594  case AsciiBS: // ... backspace
596  break;
597  case AsciiCtrC: // ... kill prompt
598  break;
599  case AsciiCtrQ: // ... restarts suspeded output
600  break;
601  case AsciiCtrS: // ... suspend output
602  break;
603  case AsciiCtrZ: // ... suspend
604  break;
605  default:
606  break;
607  }
608 
609  // treatment for ESC. character
610  if( cc == AsciiESC) { // ESC
611  G4cin.get(cc);
612  if (cc == '[' || cc == 'O') { // care for another termcap, such as konsole
613  G4cin.get(cc);
614  switch(cc) {
615  case 'A': // [UP]
616  cc = 'P' - '@';
617  PreviousCommand(); // ... show previous commad
618  break;
619  case 'B': // [DOWN]
620  cc = 'N' - '@';
621  NextCommand(); // ... show next commad
622  break;
623  case 'C': // [RIGHT]
624  cc = 'F' - '@';
625  ForwardCursor(); // ... forward cursor
626  break;
627  case 'D': // [LEFT]
628  cc = 'B' - '@';
629  BackwardCursor(); // ... backward cursor
630  break;
631  default: // who knows !?
632  cc = 0;
633  break;
634  }
635  }
636  }
637 
638  // insert character to command line and display
639  InsertCharacter(cc);
640 
641  } while( cc != '\n');
642 
643  return commandLine;
644 }
645 
649 {
651 
652  MakePrompt(msg); // update
654 
655  G4cout << promptString << std::flush;
656 
657  G4String newCommand= ReadLine(); // read line...
658  // multi-line
659  while( (newCommand.length() > 0) &&
660  ( newCommand[newCommand.length()-1] == '_') ) {
661  newCommand.remove(newCommand.length()-1);
662  G4cout << G4endl;
663  promptString= "? ";
664  G4cout << promptString << std::flush;
665  G4String newLine= ReadLine();
666  newCommand.append(newLine);
667  }
668 
669  // update history...
670  G4bool isMeaningfull= FALSE; // check NULL command
671  for (size_t i=0; i<newCommand.length(); i++) {
672  if(newCommand[i] != ' ') {
673  isMeaningfull= TRUE;
674  break;
675  }
676  }
677  if( !newCommand.empty() && isMeaningfull) StoreHistory(newCommand);
678 
679  // reset terminal
680  RestoreTerm();
681 
682  G4cout << G4endl;
683  return newCommand;
684 }
685 
688  const G4String& str2) const
690 {
691  int nlen1= str1.length();
692  int nlen2= str2.length();
693 
694  int nmin = nlen1<nlen2 ? nlen1 : nlen2;
695 
696  G4String strMatched;
697  for(size_t i=0; G4int(i)<nmin; i++){
698  if(str1[i]==str2[i]) {
699  strMatched+= str1[i];
700  } else {
701  break;
702  }
703  }
704 
705  return strMatched;
706 }
707 
708 // --------------------------------------------------------------------
709 // history
710 // --------------------------------------------------------------------
714 {
716  if(i==0) i=maxHistory;
717 
718  commandHistory[i-1]= aCommand; // 0-offset
720 }
721 
725 {
726  if(histNo>= currentHistoryNo) return "";
727 
728  G4int index= histNo%maxHistory;
729  if(index==0) index= maxHistory;
730 
731  return commandHistory[index-1]; // 0-offset
732 }
733 
734 // --------------------------------------------------------------------
735 // terminal mode
736 // --------------------------------------------------------------------
740 {
741  termios tiosbuf= tios;
742 
743  tiosbuf.c_iflag &= ~(BRKINT | ISTRIP);
744  tiosbuf.c_iflag |= (IGNBRK | IGNPAR);
745  tiosbuf.c_lflag &= ~(ICANON | IEXTEN | ECHO);
746  tiosbuf.c_cc[VMIN] = 1;
747  tiosbuf.c_cc[VTIME] = 0;
748 
749  tcsetattr(0, TCSAFLUSH, &tiosbuf);
750 }
751 
752 
756 {
757  tcsetattr(0, TCSAFLUSH, &tios);
758 }
759 
760 #endif
761