| 9838 | |
| 9839 | |
| 9840 | int Line::FileSetAttrib(char *aAttributes, char *aFilePattern, FileLoopModeType aOperateOnFolders |
| 9841 | , bool aDoRecurse, bool aCalledRecursively) |
| 9842 | // Returns the number of files and folders that could not be changed due to an error. |
| 9843 | { |
| 9844 | if (!aCalledRecursively) // i.e. Only need to do this if we're not called by ourself: |
| 9845 | { |
| 9846 | g_ErrorLevel->Assign(ERRORLEVEL_ERROR); // Set default |
| 9847 | if (!aFilePattern || !*aFilePattern) |
| 9848 | return 0; // Let ErrorLevel indicate an error, since this is probably not what the user intended. |
| 9849 | if (aOperateOnFolders == FILE_LOOP_INVALID) // In case runtime dereference of a var was an invalid value. |
| 9850 | aOperateOnFolders = FILE_LOOP_FILES_ONLY; // Set default. |
| 9851 | } |
| 9852 | |
| 9853 | // Related to the comment at the top: Since the script subroutine that resulted in the call to |
| 9854 | // this function can be interrupted during our MsgSleep(), make a copy of any params that might |
| 9855 | // currently point directly to the deref buffer. This is done because their contents might |
| 9856 | // be overwritten by the interrupting subroutine: |
| 9857 | char attributes[64]; |
| 9858 | strlcpy(attributes, aAttributes, sizeof(attributes)); |
| 9859 | |
| 9860 | // Testing shows that the ANSI version of FindFirstFile() will not accept a path+pattern longer |
| 9861 | // than 256 or so, even if the pattern would match files whose names are short enough to be legal. |
| 9862 | // Therefore, as of v1.0.25, there is also a hard limit of MAX_PATH on all these variables. |
| 9863 | // MSDN confirms this in a vague way: "In the ANSI version of FindFirstFile(), [plpFileName] is |
| 9864 | // limited to MAX_PATH characters." |
| 9865 | char file_pattern[MAX_PATH], file_path[MAX_PATH], target_filespec[MAX_PATH]; |
| 9866 | strlcpy(file_pattern, aFilePattern, sizeof(file_pattern)); |
| 9867 | |
| 9868 | if (strlen(file_pattern) >= sizeof(file_path)) |
| 9869 | return 0; // Let the above ErrorLevel indicate the problem. |
| 9870 | strlcpy(file_path, file_pattern, sizeof(file_path)); |
| 9871 | char *last_backslash = strrchr(file_path, '\\'); |
| 9872 | // Remove the filename and/or wildcard part. But leave the trailing backslash on it for |
| 9873 | // consistency with below: |
| 9874 | if (last_backslash) |
| 9875 | *(last_backslash + 1) = '\0'; |
| 9876 | else // Use current working directory, e.g. if user specified only *.* |
| 9877 | *file_path = '\0'; |
| 9878 | |
| 9879 | // For use with aDoRecurse, get just the naked file name/pattern: |
| 9880 | char *naked_filename_or_pattern = strrchr(file_pattern, '\\'); |
| 9881 | if (naked_filename_or_pattern) |
| 9882 | ++naked_filename_or_pattern; |
| 9883 | else |
| 9884 | naked_filename_or_pattern = file_pattern; |
| 9885 | |
| 9886 | if (!StrChrAny(naked_filename_or_pattern, "?*")) |
| 9887 | // Since no wildcards, always operate on this single item even if it's a folder. |
| 9888 | aOperateOnFolders = FILE_LOOP_FILES_AND_FOLDERS; |
| 9889 | |
| 9890 | LONG_OPERATION_INIT |
| 9891 | |
| 9892 | WIN32_FIND_DATA current_file; |
| 9893 | HANDLE file_search = FindFirstFile(file_pattern, ¤t_file); |
| 9894 | bool file_found = (file_search != INVALID_HANDLE_VALUE); |
| 9895 | char *cp; |
| 9896 | int failure_count = 0; |
| 9897 | enum attrib_modes {ATTRIB_MODE_NONE, ATTRIB_MODE_ADD, ATTRIB_MODE_REMOVE, ATTRIB_MODE_TOGGLE}; |