| 6279 | |
| 6280 | |
| 6281 | ResultType Line::PerformLoop(WIN32_FIND_DATA *apCurrentFile, RegItemStruct *apCurrentRegItem |
| 6282 | , LoopReadFileStruct *apCurrentReadFile, char *aCurrentField, bool &aContinueMainLoop |
| 6283 | , Line *&aJumpToLine, AttributeType aAttr, FileLoopModeType aFileLoopMode |
| 6284 | , bool aRecurseSubfolders, char *aFilePattern, __int64 aIterationLimit, bool aIsInfinite |
| 6285 | , __int64 &aIndex) |
| 6286 | // Note: Even if aFilePattern is just a directory (i.e. with not wildcard pattern), it seems best |
| 6287 | // not to append "\\*.*" to it because the pattern might be a script variable that the user wants |
| 6288 | // to conditionally resolve to various things at runtime. In other words, it's valid to have |
| 6289 | // only a single directory be the target of the loop. |
| 6290 | { |
| 6291 | BOOL file_found = FALSE; |
| 6292 | HANDLE file_search = INVALID_HANDLE_VALUE; |
| 6293 | char file_path[MAX_PATH] = ""; |
| 6294 | char naked_filename_or_pattern[MAX_PATH] = ""; |
| 6295 | // apCurrentFile is the file of the file-loop that encloses this file-loop, if any. |
| 6296 | // The below is our own current_file, which will take precedence over apCurrentFile |
| 6297 | // if this loop is a file-loop: |
| 6298 | WIN32_FIND_DATA new_current_file = {0}; |
| 6299 | if (aAttr == ATTR_LOOP_FILE) |
| 6300 | { |
| 6301 | file_search = FindFirstFile(aFilePattern, &new_current_file); |
| 6302 | file_found = (file_search != INVALID_HANDLE_VALUE); |
| 6303 | // Make a local copy of the path given in aFilePattern because as the lines of |
| 6304 | // the loop are executed, the deref buffer (which is what aFilePattern might |
| 6305 | // point to if we were called from ExecUntil()) may be overwritten -- |
| 6306 | // and we will need the path string for every loop iteration. We also need |
| 6307 | // to determine naked_filename_or_pattern: |
| 6308 | strlcpy(file_path, aFilePattern, sizeof(file_path)); |
| 6309 | char *last_backslash = strrchr(file_path, '\\'); |
| 6310 | if (last_backslash) |
| 6311 | { |
| 6312 | strlcpy(naked_filename_or_pattern, last_backslash + 1, sizeof(naked_filename_or_pattern)); |
| 6313 | *(last_backslash + 1) = '\0'; // i.e. retain the final backslash on the string. |
| 6314 | } |
| 6315 | else |
| 6316 | { |
| 6317 | strlcpy(naked_filename_or_pattern, file_path, sizeof(naked_filename_or_pattern)); |
| 6318 | *file_path = '\0'; // There is no path, so use current working directory. |
| 6319 | } |
| 6320 | for (; file_found && FileIsFilteredOut(new_current_file, aFileLoopMode, file_path) |
| 6321 | ; file_found = FindNextFile(file_search, &new_current_file)); |
| 6322 | } |
| 6323 | |
| 6324 | // Note: It seems best NOT to report warning if the loop iterates zero times |
| 6325 | // (e.g if no files are found by FindFirstFile() above), since that could |
| 6326 | // easily be an expected outcome. |
| 6327 | |
| 6328 | ResultType result; |
| 6329 | Line *jump_to_line = NULL; |
| 6330 | for (; aIsInfinite || file_found || aIndex < aIterationLimit; ++aIndex) |
| 6331 | { |
| 6332 | // Execute once the body of the loop (either just one statement or a block of statements). |
| 6333 | // Preparser has ensured that every LOOP has a non-NULL next line. |
| 6334 | // apCurrentFile is sent as an arg so that more than one nested/recursive |
| 6335 | // file-loop can be supported: |
| 6336 | result = mNextLine->ExecUntil(ONLY_ONE_LINE, &jump_to_line |
| 6337 | , file_found ? &new_current_file : apCurrentFile // inner loop's file takes precedence over outer's. |
| 6338 | , apCurrentRegItem, apCurrentReadFile, aCurrentField |