$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/CodeEditor/CodeEditor.h" 00002 #include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h" 00003 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h" 00004 00005 #include <dirent.h> //DIR and dirent 00006 #include <sys/stat.h> //for mkdir 00007 #include <cctype> //for std::toupper 00008 #include <thread> //for std::thread 00009 00010 using namespace ots; 00011 00012 #define CODE_EDITOR_DATA_PATH \ 00013 std::string(getenv("SERVICE_DATA_PATH")) + "/" + "CodeEditorData" 00014 00015 #undef __MF_SUBJECT__ 00016 #define __MF_SUBJECT__ "CodeEditor" 00017 00018 const std::string CodeEditor::SPECIAL_TYPE_FEInterface = "FEInterface"; 00019 const std::string CodeEditor::SPECIAL_TYPE_DataProcessor = "DataProcessor"; 00020 const std::string CodeEditor::SPECIAL_TYPE_Table = "Table"; 00021 const std::string CodeEditor::SPECIAL_TYPE_ControlsInterface = "ControlsInterface"; 00022 const std::string CodeEditor::SPECIAL_TYPE_Tools = "Tools"; 00023 const std::string CodeEditor::SPECIAL_TYPE_UserData = "UserData"; 00024 const std::string CodeEditor::SPECIAL_TYPE_OutputData = "OutputData"; 00025 00026 const std::string CodeEditor::SOURCE_BASE_PATH = std::string(getenv("MRB_SOURCE")) + "/"; 00027 const std::string CodeEditor::USER_DATA_PATH = std::string(getenv("USER_DATA")) + "/"; 00028 const std::string CodeEditor::OTSDAQ_DATA_PATH = std::string(getenv("OTSDAQ_DATA")) + "/"; 00029 00030 //======================================================================================================================== 00031 // CodeEditor 00032 CodeEditor::CodeEditor() 00033 : ALLOWED_FILE_EXTENSIONS_({"h", 00034 "hh", 00035 "hpp", 00036 "hxx", 00037 "c", 00038 "cc", 00039 "cpp", 00040 "cxx", 00041 "icc", 00042 "txt", 00043 "sh", 00044 "css", 00045 "html", 00046 "htm", 00047 "js", 00048 "py", 00049 "fcl", 00050 "xml"}) 00051 { 00052 std::string path = CODE_EDITOR_DATA_PATH; 00053 DIR* dir = opendir(path.c_str()); 00054 if(dir) 00055 closedir(dir); 00056 else if(-1 == mkdir(path.c_str(), 0755)) 00057 { 00058 // lets create the service folder (for first time) 00059 __SS__ << "Service directory creation failed: " << path << std::endl; 00060 __SS_THROW__; 00061 } 00062 00063 } // end CodeEditor() 00064 00065 //======================================================================================================================== 00066 // xmlRequest 00067 // all requests are handled here 00068 void CodeEditor::xmlRequest(const std::string& option, 00069 cgicc::Cgicc& cgiIn, 00070 HttpXmlDocument* xmlOut, 00071 const std::string& username) try 00072 { 00073 __COUTV__(option); 00074 00075 // request options: 00076 // 00077 // getDirectoryContent 00078 // getFileContent 00079 // saveFileContent 00080 // cleanBuild 00081 // incrementalBuild 00082 // getAllowedExtensions 00083 // 00084 00085 if(option == "getDirectoryContent") 00086 { 00087 getDirectoryContent(cgiIn, xmlOut); 00088 } 00089 else if(option == "getFileContent") 00090 { 00091 getFileContent(cgiIn, xmlOut); 00092 } 00093 else if(option == "saveFileContent") 00094 { 00095 saveFileContent(cgiIn, xmlOut, username); 00096 } 00097 else if(option == "build") 00098 { 00099 build(cgiIn, xmlOut, username); 00100 } 00101 else if(option == "getAllowedExtensions") 00102 { 00103 xmlOut->addTextElementToData( 00104 "AllowedExtensions", 00105 StringMacros::setToString(ALLOWED_FILE_EXTENSIONS_, ",")); 00106 } 00107 else 00108 { 00109 __SS__ << "Unrecognized request option '" << option << ".'" << __E__; 00110 __SS_THROW__; 00111 } 00112 } 00113 catch(const std::runtime_error& e) 00114 { 00115 __SS__ << "Error encountered while handling the Code Editor request option '" 00116 << option << "': " << e.what() << __E__; 00117 xmlOut->addTextElementToData("Error", ss.str()); 00118 } 00119 catch(...) 00120 { 00121 __SS__ << "Unknown error encountered while handling the Code Editor request option '" 00122 << option << "!'" << __E__; 00123 xmlOut->addTextElementToData("Error", ss.str()); 00124 } // end xmlRequest() 00125 00126 //======================================================================================================================== 00127 // safePathString 00128 std::string CodeEditor::safePathString(const std::string& path) 00129 { 00130 //__COUTV__(path); 00131 // remove all non ascii and non /, -, _,, space 00132 std::string fullpath = ""; 00133 for(unsigned int i = 0; i < path.length(); ++i) 00134 if((path[i] >= 'a' && path[i] <= 'z') || (path[i] >= 'A' && path[i] <= 'Z') || 00135 path[i] >= '_' || path[i] >= '-' || path[i] >= ' ' || path[i] >= '/') 00136 fullpath += path[i]; 00137 //__COUTV__(fullpath); 00138 if(!fullpath.length()) 00139 { 00140 __SS__ << "Invalid path '" << fullpath << "' found!" << __E__; 00141 __SS_THROW__; 00142 } 00143 return fullpath; 00144 } // end safePathString() 00145 00146 //======================================================================================================================== 00147 // safeExtensionString 00148 // remove all non ascii and make lower case 00149 std::string CodeEditor::safeExtensionString(const std::string& extension) 00150 { 00151 //__COUTV__(extension); 00152 00153 std::string retExt = ""; 00154 // remove all non ascii 00155 for(unsigned int i = 0; i < extension.length(); ++i) 00156 if((extension[i] >= 'a' && extension[i] <= 'z')) 00157 retExt += extension[i]; 00158 else if((extension[i] >= 'A' && extension[i] <= 'Z')) 00159 retExt += extension[i] + 32; // make lowercase 00160 00161 //__COUTV__(retExt); 00162 00163 if(ALLOWED_FILE_EXTENSIONS_.find( 00164 retExt) == // should match get directory content restrictions 00165 ALLOWED_FILE_EXTENSIONS_.end()) 00166 { 00167 __SS__ << "Invalid extension '" << retExt << "' found!" << __E__; 00168 __SS_ONLY_THROW__; 00169 } 00170 return retExt; 00171 } // end safeExtensionString() 00172 00173 //======================================================================================================================== 00174 // getDirectoryContent 00175 void CodeEditor::getDirectoryContent(cgicc::Cgicc& cgiIn, HttpXmlDocument* xmlOut) 00176 { 00177 std::string path = CgiDataUtilities::getData(cgiIn, "path"); 00178 path = safePathString(CgiDataUtilities::decodeURIComponent(path)); 00179 __COUTV__(path); 00180 __COUTV__(CodeEditor::SOURCE_BASE_PATH); 00181 00182 xmlOut->addTextElementToData("path", path); 00183 00184 const unsigned int numOfTypes = 7; 00185 std::string specialTypeNames[] = {"Front-End Plugins", 00186 "Data Processor Plugins", 00187 "Configuration Table Plugins", 00188 "Controls Interface Plugins", 00189 "Tools and Scripts", 00190 "$USER_DATA", 00191 "$OTSDAQ_DATA"}; 00192 std::string specialTypes[] = {SPECIAL_TYPE_FEInterface, 00193 SPECIAL_TYPE_DataProcessor, 00194 SPECIAL_TYPE_Table, 00195 SPECIAL_TYPE_ControlsInterface, 00196 SPECIAL_TYPE_Tools, 00197 SPECIAL_TYPE_UserData, 00198 SPECIAL_TYPE_OutputData}; 00199 00200 std::string pathMatchPrepend = "/"; // some requests come in with leading "/" and 00201 // "//" 00202 if(path.length() > 1 && path[1] == '/') 00203 pathMatchPrepend += '/'; 00204 00205 for(unsigned int i = 0; i < numOfTypes; ++i) 00206 if(path == pathMatchPrepend + specialTypeNames[i]) 00207 { 00208 __COUT__ << "Getting all " << specialTypeNames[i] << "..." << __E__; 00209 00210 // handle UserData and OutputData differently 00211 // since there is only one path to check 00212 if(specialTypes[i] == SPECIAL_TYPE_UserData) 00213 { 00214 getPathContent("/", CodeEditor::USER_DATA_PATH, xmlOut); 00215 return; 00216 } 00217 else if(specialTypes[i] == SPECIAL_TYPE_OutputData) 00218 { 00219 getPathContent("/", CodeEditor::OTSDAQ_DATA_PATH, xmlOut); 00220 return; 00221 } 00222 00223 std::map<std::string /*special type*/, 00224 std::set<std::string> /*special file paths*/> 00225 retMap = CodeEditor::getSpecialsMap(); 00226 if(retMap.find(specialTypes[i]) != retMap.end()) 00227 { 00228 for(const auto& specialTypeFile : retMap[specialTypes[i]]) 00229 { 00230 xmlOut->addTextElementToData("specialFile", specialTypeFile); 00231 } 00232 } 00233 else 00234 { 00235 __SS__ << "No files for type '" << specialTypeNames[i] << "' were found." 00236 << __E__; 00237 __SS_THROW__; 00238 } 00239 return; 00240 } 00241 00242 // if root directory, add special directory for types 00243 if(path == "/") 00244 for(unsigned int i = 0; i < numOfTypes; ++i) 00245 xmlOut->addTextElementToData("special", specialTypeNames[i]); 00246 00247 std::string contents; 00248 size_t i; 00249 if((i = path.find("$USER_DATA/")) == 0 || 00250 (i == 1 && path[0] == '/')) // if leading / or without 00251 getPathContent(CodeEditor::USER_DATA_PATH, 00252 path.substr(std::string("/$USER_DATA/").size()), 00253 xmlOut); 00254 else if((i = path.find("$OTSDAQ_DATA/")) == 0 || 00255 (i == 1 && path[0] == '/')) // if leading / or without 00256 getPathContent(CodeEditor::OTSDAQ_DATA_PATH, 00257 path.substr(std::string("/$OTSDAQ_DATA/").size()), 00258 xmlOut); 00259 else 00260 getPathContent(CodeEditor::SOURCE_BASE_PATH, path, xmlOut); 00261 00262 } // end getDirectoryContent() 00263 00264 //======================================================================================================================== 00265 // getPathContent 00266 void CodeEditor::getPathContent(const std::string& basepath, 00267 const std::string& path, 00268 HttpXmlDocument* xmlOut) 00269 { 00270 DIR* pDIR; 00271 struct dirent* entry; 00272 bool isDir; 00273 std::string name; 00274 int type; 00275 00276 if(!(pDIR = opendir((basepath + path).c_str()))) 00277 { 00278 __SS__ << "Path '" << path << "' could not be opened!" << __E__; 00279 __SS_THROW__; 00280 } 00281 00282 // add to set for alpha ordering 00283 // with insensitive compare 00284 struct InsensitiveCompare 00285 { 00286 bool operator()(const std::string& as, const std::string& bs) const 00287 { 00288 // return true, if as < bs 00289 const char* a = as.c_str(); 00290 const char* b = bs.c_str(); 00291 int d; 00292 00293 // compare each character, until difference, or end of string 00294 while((d = (std::toupper(*a) - std::toupper(*b))) == 0 && *a) 00295 ++a, ++b; 00296 00297 //__COUT__ << as << " vs " << bs << " = " << d << " " << (d<0) << __E__; 00298 00299 return d < 0; 00300 } 00301 }; 00302 std::set<std::string, InsensitiveCompare> orderedDirectories; 00303 std::set<std::string, InsensitiveCompare> orderedFiles; 00304 00305 std::string extension; 00306 00307 // else directory good, get all folders, .h, .cc, .txt files 00308 while((entry = readdir(pDIR))) 00309 { 00310 name = std::string(entry->d_name); 00311 type = int(entry->d_type); 00312 00313 //__COUT__ << type << " " << name << "\n" << std::endl; 00314 00315 if(name[0] != '.' && 00316 (type == 0 || // 0 == UNKNOWN (which can happen - seen in SL7 VM) 00317 type == 4 || type == 8)) 00318 { 00319 isDir = false; 00320 00321 if(type == 0) 00322 { 00323 // unknown type .. determine if directory 00324 DIR* pTmpDIR = 00325 opendir((CodeEditor::SOURCE_BASE_PATH + path + "/" + name).c_str()); 00326 if(pTmpDIR) 00327 { 00328 isDir = true; 00329 closedir(pTmpDIR); 00330 } 00331 // else //assume file 00332 } 00333 00334 if(type == 4) 00335 isDir = true; // flag directory types 00336 00337 // handle directories 00338 00339 if(isDir) 00340 { 00341 //__COUT__ << "Directory: " << type << " " << name << __E__; 00342 00343 orderedDirectories.emplace(name); 00344 // xmlOut->addTextElementToData("directory",name); 00345 } 00346 else // type 8 or 0 is file 00347 { 00348 //__COUT__ << "File: " << type << " " << name << "\n" << std::endl; 00349 00350 try 00351 { 00352 safeExtensionString(name.substr(name.rfind('.'))); 00353 //__COUT__ << "EditFile: " << type << " " << name << __E__; 00354 00355 orderedFiles.emplace(name); 00356 } 00357 catch(...) 00358 { 00359 __COUT__ << "Invalid file extension, skipping '" << name << "' ..." 00360 << __E__; 00361 } 00362 } 00363 } 00364 } // end directory traversal 00365 00366 closedir(pDIR); 00367 00368 __COUT__ << "Found " << orderedDirectories.size() << " directories." << __E__; 00369 __COUT__ << "Found " << orderedFiles.size() << " files." << __E__; 00370 00371 for(const auto& name : orderedDirectories) 00372 xmlOut->addTextElementToData("directory", name); 00373 for(const auto& name : orderedFiles) 00374 xmlOut->addTextElementToData("file", name); 00375 } // end getPathContent() 00376 00377 //======================================================================================================================== 00378 // getFileContent 00379 void CodeEditor::getFileContent(cgicc::Cgicc& cgiIn, HttpXmlDocument* xmlOut) 00380 { 00381 std::string path = CgiDataUtilities::getData(cgiIn, "path"); 00382 path = safePathString(CgiDataUtilities::decodeURIComponent(path)); 00383 xmlOut->addTextElementToData("path", path); 00384 00385 std::string extension = CgiDataUtilities::getData(cgiIn, "ext"); 00386 extension = safeExtensionString(extension); 00387 xmlOut->addTextElementToData("ext", extension); 00388 00389 std::string contents; 00390 size_t i; 00391 if((i = path.find("$USER_DATA/")) == 0 || 00392 (i == 1 && path[0] == '/')) // if leading / or without 00393 CodeEditor::readFile( 00394 CodeEditor::USER_DATA_PATH, 00395 path.substr(i + std::string("$USER_DATA/").size()) + "." + extension, 00396 contents); 00397 else if((i = path.find("$OTSDAQ_DATA/")) == 0 || 00398 (i == 1 && path[0] == '/')) // if leading / or without 00399 CodeEditor::readFile( 00400 CodeEditor::OTSDAQ_DATA_PATH, 00401 path.substr(std::string("/$OTSDAQ_DATA/").size()) + "." + extension, 00402 contents); 00403 else 00404 CodeEditor::readFile( 00405 CodeEditor::SOURCE_BASE_PATH, path + "." + extension, contents); 00406 00407 xmlOut->addTextElementToData("content", contents); 00408 00409 } // end getFileContent() 00410 00411 //======================================================================================================================== 00412 // readFile 00413 void CodeEditor::readFile(const std::string& basepath, 00414 const std::string& path, 00415 std::string& contents) 00416 { 00417 std::string fullpath = basepath + "/" + path; 00418 __COUTV__(fullpath); 00419 00420 std::FILE* fp = std::fopen(fullpath.c_str(), "rb"); 00421 if(!fp) 00422 { 00423 __SS__ << "Could not open file at " << path << __E__; 00424 __SS_THROW__; 00425 } 00426 00427 std::fseek(fp, 0, SEEK_END); 00428 contents.resize(std::ftell(fp)); 00429 std::rewind(fp); 00430 std::fread(&contents[0], 1, contents.size(), fp); 00431 std::fclose(fp); 00432 } // end readFile 00433 00434 //======================================================================================================================== 00435 // writeFile 00436 void CodeEditor::writeFile(const std::string& basepath, 00437 const std::string& path, 00438 const std::string& contents, 00439 const std::string& username, 00440 const unsigned long long& insertPos, 00441 const std::string& insertString) 00442 { 00443 std::string fullpath = basepath + path; 00444 __COUTV__(fullpath); 00445 00446 FILE* fp; 00447 00448 // get old file size 00449 fp = fopen(fullpath.c_str(), "rb"); 00450 if(!fp) 00451 { 00452 __SS__ << "Could not open file for saving at " << fullpath << __E__; 00453 __SS_THROW__; 00454 } 00455 std::fseek(fp, 0, SEEK_END); 00456 long long int oldSize = std::ftell(fp); 00457 fclose(fp); 00458 00459 fp = fopen(fullpath.c_str(), "wb"); 00460 if(!fp) 00461 { 00462 __SS__ << "Could not open file for saving at " << fullpath << __E__; 00463 __SS_THROW__; 00464 } 00465 00466 if(insertPos == (unsigned long long)-1) 00467 std::fwrite(&contents[0], 1, contents.size(), fp); 00468 else // do insert 00469 { 00470 std::fwrite(&contents[0], 1, insertPos, fp); 00471 std::fwrite(&insertString[0], 1, insertString.size(), fp); 00472 std::fwrite(&contents[insertPos], 1, contents.size() - insertPos, fp); 00473 } 00474 std::fclose(fp); 00475 00476 // log changes 00477 { 00478 std::string logpath = CODE_EDITOR_DATA_PATH + "/codeEditorChangeLog.txt"; 00479 fp = fopen(logpath.c_str(), "a"); 00480 if(!fp) 00481 { 00482 __SS__ << "Could not open change log for change tracking at " << logpath 00483 << __E__; 00484 __SS_THROW__; 00485 } 00486 fprintf(fp, 00487 "time=%lld author%s old-size=%lld new-size=%lld path=%s\n", 00488 (long long)time(0), 00489 username.c_str(), 00490 oldSize, 00491 (long long)contents.size(), 00492 fullpath.c_str()); 00493 00494 fclose(fp); 00495 __COUT__ << "Changes logged to: " << logpath << __E__; 00496 } // end log changes 00497 00498 } // end writeFile 00499 00500 //======================================================================================================================== 00501 // saveFileContent 00502 void CodeEditor::saveFileContent(cgicc::Cgicc& cgiIn, 00503 HttpXmlDocument* xmlOut, 00504 const std::string& username) 00505 { 00506 std::string path = CgiDataUtilities::getData(cgiIn, "path"); 00507 path = safePathString(CgiDataUtilities::decodeURIComponent(path)); 00508 xmlOut->addTextElementToData("path", path); 00509 00510 std::string extension = CgiDataUtilities::getData(cgiIn, "ext"); 00511 extension = safeExtensionString(extension); 00512 xmlOut->addTextElementToData("ext", extension); 00513 00514 std::string contents = CgiDataUtilities::postData(cgiIn, "content"); 00515 //__COUTV__(contents); 00516 contents = StringMacros::decodeURIComponent(contents); 00517 00518 CodeEditor::writeFile( 00519 CodeEditor::SOURCE_BASE_PATH, path + "." + extension, contents, username); 00520 00521 } // end saveFileContent 00522 00523 //======================================================================================================================== 00524 // build 00525 // cleanBuild and incrementalBuild 00526 void CodeEditor::build(cgicc::Cgicc& cgiIn, 00527 HttpXmlDocument* xmlOut, 00528 const std::string& username) 00529 { 00530 bool clean = CgiDataUtilities::getDataAsInt(cgiIn, "clean") ? true : false; 00531 00532 __MCOUT_INFO__("Build (clean=" << clean << ") launched by '" << username << "'..." 00533 << __E__); 00534 00535 // launch as thread so it does not lock up rest of code 00536 std::thread( 00537 [](bool clean) { 00538 00539 std::string cmd; 00540 if(clean) 00541 { 00542 // clean 00543 { 00544 cmd = "mrb z 2>&1"; 00545 00546 std::array<char, 128> buffer; 00547 std::string result; 00548 std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose); 00549 if(!pipe) 00550 __THROW__("popen() failed!"); 00551 00552 size_t i; 00553 size_t j; 00554 00555 while(!feof(pipe.get())) 00556 { 00557 if(fgets(buffer.data(), 128, pipe.get()) != nullptr) 00558 { 00559 result += buffer.data(); 00560 00561 // each time there is a new line print out 00562 i = result.find('\n'); 00563 __COUTV__(result.substr(0, i)); 00564 __MOUT__ << result.substr(0, i); 00565 result = result.substr(i + 1); // discard before new line 00566 } 00567 } 00568 00569 __COUTV__(result); 00570 __MOUT__ << result.substr(0, i); 00571 } 00572 00573 sleep(1); 00574 // mrbsetenv 00575 { 00576 cmd = "source mrbSetEnv 2>&1"; 00577 00578 std::array<char, 128> buffer; 00579 std::string result; 00580 std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose); 00581 if(!pipe) 00582 __THROW__("popen() failed!"); 00583 00584 size_t i; 00585 size_t j; 00586 00587 while(!feof(pipe.get())) 00588 { 00589 if(fgets(buffer.data(), 128, pipe.get()) != nullptr) 00590 { 00591 result += buffer.data(); 00592 00593 // each time there is a new line print out 00594 i = result.find('\n'); 00595 __COUTV__(result.substr(0, i)); 00596 __MOUT__ << result.substr(0, i); 00597 result = result.substr(i + 1); // discard before new line 00598 } 00599 } 00600 00601 __COUTV__(result); 00602 __MOUT__ << result.substr(0, i); 00603 } 00604 sleep(1); 00605 } 00606 00607 // build 00608 { 00609 cmd = "mrb b 2>&1"; 00610 00611 std::array<char, 128> buffer; 00612 std::string result; 00613 std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose); 00614 if(!pipe) 00615 __THROW__("popen() failed!"); 00616 00617 size_t i; 00618 size_t j; 00619 00620 while(!feof(pipe.get())) 00621 { 00622 if(fgets(buffer.data(), 128, pipe.get()) != nullptr) 00623 { 00624 result += buffer.data(); 00625 00626 // each time there is a new line print out 00627 i = result.find('\n'); 00628 //__COUTV__(result.substr(0,i)); 00629 __MOUT__ << result.substr(0, i); 00630 result = result.substr(i + 1); // discard before new line 00631 } 00632 } 00633 00634 //__COUTV__(result); 00635 __MOUT__ << result.substr(0, i); 00636 } 00637 }, 00638 clean) 00639 .detach(); 00640 00641 } // end build() 00642 00643 //======================================================================================================================== 00644 std::map<std::string /*special type*/, std::set<std::string> /*special file paths*/> 00645 CodeEditor::getSpecialsMap(void) 00646 { 00647 std::map<std::string /*special type*/, std::set<std::string> /*special file paths*/> 00648 retMap; 00649 std::string path = std::string(getenv("MRB_SOURCE")); 00650 00651 __COUTV__(path); 00652 00653 const unsigned int numOfSpecials = 7; 00654 std::string specialFolders[] = {"FEInterfaces", 00655 "DataProcessorPlugins", 00656 "UserTableDataFormats", 00657 "TablePluginDataFormats", 00658 "SlowControlsInterfacePlugins", 00659 "FEInterfacePlugins", 00660 "tools"}; 00661 std::string specialMapTypes[] = {CodeEditor::SPECIAL_TYPE_FEInterface, 00662 CodeEditor::SPECIAL_TYPE_DataProcessor, 00663 CodeEditor::SPECIAL_TYPE_Table, 00664 CodeEditor::SPECIAL_TYPE_Table, 00665 CodeEditor::SPECIAL_TYPE_ControlsInterface, 00666 CodeEditor::SPECIAL_TYPE_FEInterface, 00667 CodeEditor::SPECIAL_TYPE_Tools}; 00668 00669 // Note: can not do lambda recursive function if using auto to declare the function, 00670 // and must capture reference to the function. Also, must capture specialFolders 00671 // reference for use internally (const values already are captured). 00672 std::function<void( 00673 const std::string&, const std::string&, const unsigned int, const int)> 00674 localRecurse = [&specialFolders, &specialMapTypes, &retMap, &localRecurse]( 00675 const std::string& path, 00676 const std::string& offsetPath, 00677 const unsigned int depth, 00678 const int specialIndex) { 00679 00680 //__COUTV__(path); 00681 //__COUTV__(depth); 00682 00683 DIR* pDIR; 00684 struct dirent* entry; 00685 bool isDir; 00686 if(!(pDIR = opendir(path.c_str()))) 00687 { 00688 __SS__ << "Plugin base path '" << path << "' could not be opened!" 00689 << __E__; 00690 __SS_THROW__; 00691 } 00692 00693 // else directory good, get all folders and look for special folders 00694 std::string name; 00695 int type; 00696 int childSpecialIndex; 00697 while((entry = readdir(pDIR))) 00698 { 00699 name = std::string(entry->d_name); 00700 type = int(entry->d_type); 00701 00702 //__COUT__ << type << " " << name << "\n" << std::endl; 00703 00704 if(name[0] != '.' && 00705 (type == 0 || // 0 == UNKNOWN (which can happen - seen in SL7 VM) 00706 type == 4 || type == 8)) 00707 { 00708 isDir = false; 00709 00710 if(type == 0) 00711 { 00712 // unknown type .. determine if directory 00713 DIR* pTmpDIR = opendir((path + "/" + name).c_str()); 00714 if(pTmpDIR) 00715 { 00716 isDir = true; 00717 closedir(pTmpDIR); 00718 } 00719 // else //assume file 00720 } 00721 00722 if(type == 4) 00723 isDir = true; // flag directory types 00724 00725 // handle directories 00726 00727 if(isDir) 00728 { 00729 //__COUT__ << "Directory: " << type << " " << name << __E__; 00730 00731 childSpecialIndex = -1; 00732 for(unsigned int i = 0; i < numOfSpecials; ++i) 00733 if(name == specialFolders[i]) 00734 { 00735 //__COUT__ << "Found special folder '" << 00736 // specialFolders[i] << 00737 // "' at path " << path << __E__; 00738 00739 childSpecialIndex = i; 00740 break; 00741 } 00742 00743 // recurse deeper! 00744 if(depth < 4) // limit search depth 00745 localRecurse(path + "/" + name, 00746 offsetPath + "/" + name, 00747 depth + 1, 00748 childSpecialIndex); 00749 } 00750 else if(specialIndex >= 0) 00751 { 00752 // get special files!! 00753 00754 if(name.find(".h") == name.length() - 2 || 00755 name.find(".cc") == name.length() - 3 || 00756 name.find(".txt") == name.length() - 4 || 00757 name.find(".sh") == name.length() - 3 || 00758 name.find(".py") == name.length() - 3) 00759 { 00760 //__COUT__ << "Found special '" << 00761 // specialFolders[specialIndex] << 00762 // "' file '" << name << "' at path " << 00763 // path << " " << specialIndex << __E__; 00764 00765 retMap[specialMapTypes[specialIndex]].emplace(offsetPath + 00766 "/" + name); 00767 } 00768 } 00769 } 00770 } // end directory traversal 00771 00772 closedir(pDIR); 00773 00774 }; //end localRecurse() definition 00775 00776 // start recursive traversal to find special folders 00777 localRecurse(path, "" /*offsetPath*/, 0 /*depth*/, -1 /*specialIndex*/); 00778 00779 //__COUTV__(StringMacros::mapToString(retMap)); 00780 return retMap; 00781 } // end getSpecialsMap()