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