Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/interfaces/core/src/G4UItcsh.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

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