https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e2b04fe75da490448b3eb…
commit e2b04fe75da490448b3eb49806163003bce097c6
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Thu May 18 12:43:23 2023 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Thu May 18 13:07:31 2023 +0200
[ATTRIB] Improve command-line parsing. (#5288)
Fix arguments parsing and redundant code in case no file specification
has been given.
(Handles both "attrib" and "attrib +h /s" as given in example.)
---
base/applications/cmdutils/attrib/attrib.c | 197 ++++++++++++++---------------
1 file changed, 92 insertions(+), 105 deletions(-)
diff --git a/base/applications/cmdutils/attrib/attrib.c
b/base/applications/cmdutils/attrib/attrib.c
index 9d22255d8eb..821bfd52faf 100644
--- a/base/applications/cmdutils/attrib/attrib.c
+++ b/base/applications/cmdutils/attrib/attrib.c
@@ -283,162 +283,149 @@ ChangeAttribute(
int wmain(int argc, WCHAR *argv[])
{
- INT i;
- WCHAR szPath[MAX_PATH] = L""; // For case we only use 'attrib +h
/s' there is no szPath
- WCHAR szFileName [MAX_PATH];
- BOOL bRecurse = FALSE;
- BOOL bDirectories = FALSE;
- DWORD dwAttrib = 0;
- DWORD dwMask = 0;
- LPWSTR p;
+ INT i;
+ BOOL bRecurse = FALSE;
+ BOOL bDirectories = FALSE;
+ DWORD dwAttrib = 0;
+ DWORD dwMask = 0;
+ BOOL bFound = FALSE;
+ PWSTR pszFileName;
+ WCHAR szFilePath[MAX_PATH + 2] = L""; // + 2 to reserve an extra path
separator and a NULL-terminator.
/* Initialize the Console Standard Streams */
ConInitStdStreams();
- /* Print help */
- if (argc > 1 && wcscmp(argv[1], L"/?") == 0)
- {
- ConResPuts(StdOut, STRING_ATTRIB_HELP);
- return 0;
- }
-
- /* check for options */
- for (i = 1; i < argc; i++)
- {
- if (wcsicmp(argv[i], L"/s") == 0)
- bRecurse = TRUE;
- else if (wcsicmp(argv[i], L"/d") == 0)
- bDirectories = TRUE;
- }
-
- /* create attributes and mask */
+ /* Check for options and file specifications */
for (i = 1; i < argc; i++)
{
- if (*argv[i] == L'+')
+ if (*argv[i] == L'/')
{
- if (wcslen(argv[i]) != 2)
+ /* Print help and bail out if needed */
+ if (wcscmp(argv[i], L"/?") == 0)
{
- ConResPrintf(StdOut, STRING_ERROR_INVALID_PARAM_FORMAT, argv[i]);
- return -1;
+ ConResPuts(StdOut, STRING_ATTRIB_HELP);
+ return 0;
}
-
- switch (towupper(argv[i][1]))
+ else
+ /* Retrieve the enumeration modes */
+ if (wcsicmp(argv[i], L"/s") == 0)
+ bRecurse = TRUE;
+ else if (wcsicmp(argv[i], L"/d") == 0)
+ bDirectories = TRUE;
+ else
{
- case L'A':
- dwMask |= FILE_ATTRIBUTE_ARCHIVE;
- dwAttrib |= FILE_ATTRIBUTE_ARCHIVE;
- break;
-
- case L'H':
- dwMask |= FILE_ATTRIBUTE_HIDDEN;
- dwAttrib |= FILE_ATTRIBUTE_HIDDEN;
- break;
-
- case L'R':
- dwMask |= FILE_ATTRIBUTE_READONLY;
- dwAttrib |= FILE_ATTRIBUTE_READONLY;
- break;
-
- case L'S':
- dwMask |= FILE_ATTRIBUTE_SYSTEM;
- dwAttrib |= FILE_ATTRIBUTE_SYSTEM;
- break;
-
- default:
- ConResPrintf(StdOut, STRING_ERROR_INVALID_PARAM_FORMAT, argv[i]);
- return -1;
+ /* Unknown option */
+ ConResPrintf(StdErr, STRING_ERROR_INVALID_PARAM_FORMAT, argv[i]);
+ return -1;
}
}
- else if (*argv[i] == L'-')
+ else
+ /* Build attributes and mask */
+ if ((*argv[i] == L'+') || (*argv[i] == L'-'))
{
+ BOOL bAdd = (*argv[i] == L'+');
+
if (wcslen(argv[i]) != 2)
{
- ConResPrintf(StdOut, STRING_ERROR_INVALID_PARAM_FORMAT, argv[i]);
+ ConResPrintf(StdErr, STRING_ERROR_INVALID_PARAM_FORMAT, argv[i]);
return -1;
}
switch (towupper(argv[i][1]))
{
case L'A':
- dwMask |= FILE_ATTRIBUTE_ARCHIVE;
- dwAttrib &= ~FILE_ATTRIBUTE_ARCHIVE;
+ dwMask |= FILE_ATTRIBUTE_ARCHIVE;
+ if (bAdd)
+ dwAttrib |= FILE_ATTRIBUTE_ARCHIVE;
+ else
+ dwAttrib &= ~FILE_ATTRIBUTE_ARCHIVE;
break;
- case L'H':
- dwMask |= FILE_ATTRIBUTE_HIDDEN;
- dwAttrib &= ~FILE_ATTRIBUTE_HIDDEN;
+ case L'S':
+ dwMask |= FILE_ATTRIBUTE_SYSTEM;
+ if (bAdd)
+ dwAttrib |= FILE_ATTRIBUTE_SYSTEM;
+ else
+ dwAttrib &= ~FILE_ATTRIBUTE_SYSTEM;
break;
- case L'R':
- dwMask |= FILE_ATTRIBUTE_READONLY;
- dwAttrib &= ~FILE_ATTRIBUTE_READONLY;
+ case L'H':
+ dwMask |= FILE_ATTRIBUTE_HIDDEN;
+ if (bAdd)
+ dwAttrib |= FILE_ATTRIBUTE_HIDDEN;
+ else
+ dwAttrib &= ~FILE_ATTRIBUTE_HIDDEN;
break;
- case L'S':
- dwMask |= FILE_ATTRIBUTE_SYSTEM;
- dwAttrib &= ~FILE_ATTRIBUTE_SYSTEM;
+ case L'R':
+ dwMask |= FILE_ATTRIBUTE_READONLY;
+ if (bAdd)
+ dwAttrib |= FILE_ATTRIBUTE_READONLY;
+ else
+ dwAttrib &= ~FILE_ATTRIBUTE_READONLY;
break;
default:
- ConResPrintf(StdOut, STRING_ERROR_INVALID_PARAM_FORMAT, argv[i]);
+ ConResPrintf(StdErr, STRING_ERROR_INVALID_PARAM_FORMAT, argv[i]);
return -1;
}
}
+ else
+ {
+ /* At least one file specification found */
+ bFound = TRUE;
+ }
}
- if (argc == 1)
+ /* If no file specification was found, operate on all files of the current directory
*/
+ if (!bFound)
{
- DWORD len;
-
- len = GetCurrentDirectory(MAX_PATH, szPath);
- if (szPath[len-1] != L'\\')
+ DWORD len = GetCurrentDirectoryW(_countof(szFilePath) - 2, szFilePath);
+ if (szFilePath[len - 1] != L'\\')
{
- szPath[len] = L'\\';
- szPath[len + 1] = UNICODE_NULL;
+ szFilePath[len] = L'\\';
+ szFilePath[len + 1] = UNICODE_NULL;
}
- wcscpy(szFileName, L"*.*");
- PrintAttribute(szPath, szFileName, bRecurse, bDirectories);
+ pszFileName = L"*.*";
+
+ if (dwMask == 0)
+ bFound = PrintAttribute(szFilePath, pszFileName, bRecurse, bDirectories);
+ else
+ bFound = ChangeAttribute(szFilePath, pszFileName, bRecurse, bDirectories,
dwMask, dwAttrib);
+
+ if (!bFound)
+ ConResPrintf(StdOut, STRING_FILE_NOT_FOUND, pszFileName);
+
return 0;
}
- /* get full file name */
+ /* Operate on each file specification */
for (i = 1; i < argc; i++)
{
- if (*argv[i] == L'+' || *argv[i] == L'-' || *argv[i] ==
L'/')
+ /* Skip options */
+ if (*argv[i] == L'/' || *argv[i] == L'+' || *argv[i] ==
L'-')
continue;
- GetFullPathNameW(argv[i], MAX_PATH, szPath, &p);
- wcscpy(szFileName, p);
- *p = 0;
-
- if (dwMask == 0)
+ GetFullPathNameW(argv[i], _countof(szFilePath) - 2, szFilePath,
&pszFileName);
+ if (pszFileName)
{
- if (!PrintAttribute(szPath, szFileName, bRecurse, bDirectories))
- {
- ConResPrintf(StdOut, STRING_FILE_NOT_FOUND, argv[i]);
- }
+ /* Move the file part so as to separate and NULL-terminate the directory */
+ MoveMemory(pszFileName + 1, pszFileName,
+ sizeof(szFilePath) - (pszFileName -szFilePath + 1) *
sizeof(*szFilePath));
+ *pszFileName++ = UNICODE_NULL;
}
- else if (!ChangeAttribute(szPath, szFileName, bRecurse, bDirectories, dwMask,
dwAttrib))
+ else
{
- ConResPrintf(StdOut, STRING_FILE_NOT_FOUND, argv[i]);
+ pszFileName = L"";
}
- }
-// Code below handles the special case of 'attrib +h /s' and similar
-
- if (bRecurse && dwMask && (wcscmp(szPath, L"") == 0))
- {
- DWORD len;
+ if (dwMask == 0)
+ bFound = PrintAttribute(szFilePath, pszFileName, bRecurse, bDirectories);
+ else
+ bFound = ChangeAttribute(szFilePath, pszFileName, bRecurse, bDirectories,
dwMask, dwAttrib);
- len = GetCurrentDirectory(MAX_PATH, szPath);
- if (szPath[len-1] != L'\\')
- {
- szPath[len] = L'\\';
- szPath[len + 1] = UNICODE_NULL;
- }
- wcscpy(szFileName, L"*.*");
- if (!ChangeAttribute(szPath, szFileName, bRecurse, bDirectories, dwMask,
dwAttrib))
- ConResPrintf(StdOut, STRING_FILE_NOT_FOUND, szFileName);
+ if (!bFound)
+ ConResPrintf(StdOut, STRING_FILE_NOT_FOUND, argv[i]);
}
return 0;