Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4UItcsh.cc
Go to the documentation of this file.
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
43static const char AsciiCtrA = '\001';
44static const char AsciiCtrB = '\002';
45static const char AsciiCtrC = '\003';
46static const char AsciiCtrD = '\004';
47static const char AsciiCtrE = '\005';
48static const char AsciiCtrF = '\006';
49static const char AsciiCtrK = '\013';
50static const char AsciiCtrL = '\014';
51static const char AsciiCtrN = '\016';
52static const char AsciiCtrP = '\020';
53static const char AsciiCtrQ = '\021';
54static const char AsciiCtrS = '\023';
55static const char AsciiCtrZ = '\032';
56static const char AsciiTAB = '\011';
57static const char AsciiBS = '\010';
58static const char AsciiDEL = '\177';
59static const char AsciiESC = '\033';
60
61static const int AsciiPrintableMin = 32;
62
63// history file
64static const G4String historyFileName = "/.g4_hist";
65
66/////////////////////////////////////////////////////////
67G4UItcsh::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/////////////////////
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;
121
122 for (G4int i = n0hist; i <= currentHistoryNo; i++) {
123 histfile << RestoreHistory(i) << G4endl;
124 }
125
126 histfile.close();
127}
128
129//////////////////////////////////////////
130void G4UItcsh::MakePrompt(const char* msg)
131//////////////////////////////////////////
132{
133 if (promptSetting.length() <= 1) {
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 {
151 stateStr = statM->GetStateString(statM->GetCurrentState());
152 }
153 promptString.append(stateStr);
154 i++;
155 } break;
156 case '/': // current working directory
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 {
173 }
174 }
175
176 // append last chaacter
177 if (i == G4int(promptSetting.length() - 1)) promptString += promptSetting[i];
178}
179
180//////////////////////////////
182//////////////////////////////
183{
184 RestoreTerm();
185}
186
187// --------------------------------------------------------------------
188// commad line operations
189// --------------------------------------------------------------------
190//////////////////////////////////////
192//////////////////////////////////////
193{
194 commandLine = "";
195 cursorPosition = 1;
196}
197
198///////////////////////////////////////
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 }
221}
222
223///////////////////////////////////
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
250}
251
252////////////////////////////////
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//////////////////////////
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/////////////////////////////////
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////////////////////////////
311////////////////////////////
312{
313 if (! clearString.empty()) {
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//////////////////////////////
325//////////////////////////////
326{
327 if (IsCursorLast()) return;
328
329 G4cout << commandLine[cursorPosition - 1] << std::flush;
331}
332
333///////////////////////////////
335///////////////////////////////
336{
337 if (cursorPosition == 1) return;
338
340 G4cout << AsciiBS << std::flush;
341}
342
343//////////////////////////////
345//////////////////////////////
346{
347 for (G4int i = cursorPosition; i > 1; --i) {
348 G4cout << AsciiBS;
349 }
350 G4cout << std::flush;
351 cursorPosition = 1;
352}
353
354//////////////////////////////
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////////////////////////////////
367////////////////////////////////
368{
370
371 // retain current input
373
374 if (relativeHistoryIndex >= -nhmax + 1 && relativeHistoryIndex <= 0) {
375 ClearLine();
378
379 G4cout << commandLine << std::flush;
380 cursorPosition = G4int(commandLine.length() + 1);
381 }
382}
383
384////////////////////////////
386////////////////////////////
387{
389
390 if (relativeHistoryIndex >= -nhmax && relativeHistoryIndex <= -1) {
391 ClearLine();
393
394 if (relativeHistoryIndex == 0)
396 else
398
399 G4cout << commandLine << std::flush;
400 cursorPosition = G4int(commandLine.length() + 1);
401 }
402}
403
404///////////////////////////////////
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"
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////////////////////////////////
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"
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 = input;
554 cursorPosition = G4int(commandLine.length() + 1);
555}
556
557// --------------------------------------------------------------------
558// commad line
559// --------------------------------------------------------------------
560/////////////////////////////
562/////////////////////////////
563{
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
574 break;
575 case AsciiCtrB: // ... backward cursor
577 break;
578 case AsciiCtrD: // ... delete/exit/show matched list
579 if (commandLine.length() != 0 && IsCursorLast())
581 else if (commandLine.empty()) {
582 return G4String("exit");
583 }
584 else
586 break;
587 case AsciiCtrE: // ... move cursor to the end
589 break;
590 case AsciiCtrF: // ... forward cursor
592 break;
593 case AsciiCtrK: // ... clear after the cursor
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
604 break;
605 case AsciiTAB: // ... command completion
606 if ((! commandLine.empty()) && IsCursorLast()) CompleteCommand();
607 break;
608 case AsciiDEL: // ... backspace
610 break;
611 case AsciiBS: // ... backspace
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////////////////////////////////////////////////////////
665////////////////////////////////////////////////////////
666{
668
669 MakePrompt(msg); // update
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////////////////////////////////////////////////////////////////////
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//////////////////////////////////////////////
729//////////////////////////////////////////////
730{
732 if (i == 0) i = maxHistory;
733
734 commandHistory[i - 1] = aCommand; // 0-offset
736}
737
738///////////////////////////////////////////////
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///////////////////////////////////
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////////////////////////////
770////////////////////////////
771{
772 tcsetattr(0, TCSAFLUSH, &tios);
773}
774
775#endif
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
#define G4cin
Definition G4ios.hh:66
const G4ApplicationState & GetCurrentState() const
G4String GetStateString(const G4ApplicationState &aState) const
static G4StateManager * GetStateManager()
G4int GetCommandEntry() const
G4UIcommand * GetCommand(G4int i)
const G4String & GetPathName() const
G4int GetTreeEntry() const
G4UIcommandTree * GetTree(G4int i)
const G4String & GetCommandName() const
void MoveCursorTop()
Definition G4UItcsh.cc:344
void InsertCharacter(char cc)
Definition G4UItcsh.cc:199
void PreviousCommand()
Definition G4UItcsh.cc:366
G4String GetFirstMatchedString(const G4String &str1, const G4String &str2) const
Definition G4UItcsh.cc:703
void CompleteCommand()
Definition G4UItcsh.cc:445
void NextCommand()
Definition G4UItcsh.cc:385
G4String GetCommandLineString(const char *msg=nullptr) override
Definition G4UItcsh.cc:664
G4String RestoreHistory(G4int index)
Definition G4UItcsh.cc:739
void RestoreTerm()
Definition G4UItcsh.cc:769
void ForwardCursor()
Definition G4UItcsh.cc:324
G4String ReadLine()
Definition G4UItcsh.cc:561
G4int cursorPosition
Definition G4UItcsh.hh:146
void MoveCursorEnd()
Definition G4UItcsh.cc:355
void ResetTerminal() override
Definition G4UItcsh.cc:181
~G4UItcsh() override
Definition G4UItcsh.cc:106
G4int currentHistoryNo
Definition G4UItcsh.hh:151
void DeleteCharacter()
Definition G4UItcsh.cc:253
termios tios
Definition G4UItcsh.hh:154
void SetTermToInputMode()
Definition G4UItcsh.cc:754
void ListMatchedCommand()
Definition G4UItcsh.cc:405
G4String clearString
Definition G4UItcsh.hh:155
G4bool IsCursorLast() const
Definition G4UItcsh.hh:161
G4String commandLine
Definition G4UItcsh.hh:145
void InitializeCommandLine()
Definition G4UItcsh.cc:191
G4String commandLineBuf
Definition G4UItcsh.hh:147
G4UItcsh(const G4String &prompt="%s> ", G4int maxhist=100)
Definition G4UItcsh.cc:67
void MakePrompt(const char *msg=nullptr) override
Definition G4UItcsh.cc:130
std::vector< G4String > commandHistory
Definition G4UItcsh.hh:149
G4int maxHistory
Definition G4UItcsh.hh:150
void ClearLine()
Definition G4UItcsh.cc:274
void BackwardCursor()
Definition G4UItcsh.cc:334
void ClearAfterCursor()
Definition G4UItcsh.cc:293
void ClearScreen()
Definition G4UItcsh.cc:310
void StoreHistory(G4String aCommand)
Definition G4UItcsh.cc:728
void BackspaceCharacter()
Definition G4UItcsh.cc:224
G4int relativeHistoryIndex
Definition G4UItcsh.hh:152
virtual void ListCommand(const G4String &input, const G4String &candidate="") const
G4UIcommandTree * GetCommandTree(const G4String &dir) const
G4String currentCommandDir
G4String promptString
G4String promptSetting
G4String GetCommandPathTail(const G4String &apath) const
G4String GetAbsCommandDirPath(const G4String &apath) const