| 11577 | |
| 11578 | |
| 11579 | ResultType Line::PerformLoopReadFile(ResultToken *aResultToken, Line *&aJumpToLine, Line *aUntil |
| 11580 | , LPTSTR aReadFileName, LPTSTR aWriteFileName) |
| 11581 | { |
| 11582 | TextFile tfile; |
| 11583 | bool file_is_open = tfile.Open(aReadFileName, DEFAULT_READ_FLAGS, g->Encoding & CP_AHKCP); |
| 11584 | if (!file_is_open) |
| 11585 | { |
| 11586 | // Failed to open the input file. If an ELSE is present, executing it if the file wasn't found |
| 11587 | // seems much more useful than executing ELSE only for empty files; but if there's no ELSE, it's |
| 11588 | // probably best to throw an error. |
| 11589 | DWORD error = GetLastError(); |
| 11590 | if ( !(mRelatedLine->mActionType == ACT_ELSE && (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND)) ) |
| 11591 | return g_script.Win32Error(error); |
| 11592 | // Otherwise, execute the ELSE below. |
| 11593 | } |
| 11594 | |
| 11595 | // Make a persistent copy in case aWriteFileName's contents are in the deref buffer: |
| 11596 | if ( !(aWriteFileName = _tcsdup(aWriteFileName)) ) |
| 11597 | return MemoryError(); |
| 11598 | |
| 11599 | LoopReadFileStruct loop_info { aWriteFileName }; |
| 11600 | size_t line_length; |
| 11601 | ResultType result = CONDITION_FALSE; |
| 11602 | Line *jump_to_line = nullptr; |
| 11603 | global_struct &g = *::g; // Primarily for performance in this case. |
| 11604 | g.mLoopReadFile = &loop_info; |
| 11605 | |
| 11606 | if (file_is_open) |
| 11607 | for (;; ++g.mLoopIteration) |
| 11608 | { |
| 11609 | if ( !(line_length = tfile.ReadLine(loop_info.mCurrentLine, _countof(loop_info.mCurrentLine) - 1)) ) // -1 to ensure there's room for a null-terminator. |
| 11610 | break; |
| 11611 | if (loop_info.mCurrentLine[line_length - 1] == '\n') // Remove end-of-line character. |
| 11612 | --line_length; |
| 11613 | loop_info.mCurrentLine[line_length] = '\0'; |
| 11614 | |
| 11615 | PERFORMLOOP_EXECUTE_BODY |
| 11616 | PERFORMLOOP_EVALUATE_UNTIL |
| 11617 | } |
| 11618 | |
| 11619 | if (result == CONDITION_FALSE) |
| 11620 | { |
| 11621 | // No lines were read, so execute this loop's ELSE if present. It's done here rather than |
| 11622 | // in ExecUntil so that FileAppend can be used within the ELSE to write to mWriteFile. |
| 11623 | if (mRelatedLine->mActionType == ACT_ELSE) |
| 11624 | result = mRelatedLine->mNextLine->ExecUntil(ONLY_ONE_LINE, aResultToken, &aJumpToLine); |
| 11625 | else |
| 11626 | result = OK; // Never return CONDITION_FALSE, otherwise ExecUntil() will execute the ELSE a second time. |
| 11627 | } |
| 11628 | |
| 11629 | if (loop_info.mWriteFile) |
| 11630 | { |
| 11631 | loop_info.mWriteFile->Close(); |
| 11632 | delete loop_info.mWriteFile; |
| 11633 | } |
| 11634 | |
| 11635 | return result; |
| 11636 | } |
no test coverage detected