/*
 *  ATTRIB.C - attrib internal command.
 *
 *
 *  History:
 *
 *    04-Dec-1998 Eric Kohl
 *        started
 *
 *    09-Dec-1998 Eric Kohl
 *        implementation works, except recursion ("attrib /s").
 *
 *    05-Jan-1999 Eric Kohl
 *        major rewrite.
 *        fixed recursion ("attrib /s").
 *        started directory support ("attrib /s /d").
 *        updated help text.
 *
 *    14-Jan-1999 Eric Kohl
 *        Unicode ready!
 *
 *    19-Jan-1999 Eric Kohl
 *        Redirection ready!
 *
 *    21-Jan-1999 Eric Kohl
 *        Added check for invalid filenames.
 *
 *    23-Jan-1999 Eric Kohl
 *        Added handling of multiple filenames.
 *
 *    02-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
 *        Remove all hardcoded strings in En.rc
 */

#include "precomp.h"

#ifdef INCLUDE_CMD_ATTRIB

static VOID
PrintAttribute (LPTSTR pszPath, LPTSTR pszFile, BOOL bRecurse)
{
    WIN32_FIND_DATA findData;
    HANDLE hFind;
    TCHAR  szFullName[MAX_PATH];
    LPTSTR pszFileName;

    /* prepare full file name buffer */
    _tcscpy (szFullName, pszPath);
    pszFileName = szFullName + _tcslen (szFullName);

    /* display all subdirectories */
    if (bRecurse)
    {
        /* append file name */
        _tcscpy (pszFileName, pszFile);

        hFind = FindFirstFile (szFullName, &findData);
        if (hFind == INVALID_HANDLE_VALUE)
        {
            ErrorMessage (GetLastError (), pszFile);
            return;
        }

        do
        {
            if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
                continue;

            if (!_tcscmp (findData.cFileName, _T(".")) ||
                !_tcscmp (findData.cFileName, _T("..")))
                continue;

            _tcscpy (pszFileName, findData.cFileName);
            _tcscat (pszFileName, _T("\\"));
            PrintAttribute (szFullName, pszFile, bRecurse);
        }
        while (FindNextFile (hFind, &findData));
        FindClose (hFind);
    }

    /* append file name */
    _tcscpy (pszFileName, pszFile);

    /* display current directory */
    hFind = FindFirstFile (szFullName, &findData);
    if (hFind == INVALID_HANDLE_VALUE)
    {
        ErrorMessage (GetLastError (), pszFile);
        return;
    }

    do
    {
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            continue;

        _tcscpy (pszFileName, findData.cFileName);

        ConOutPrintf(_T("%c  %c%c%c     %s\n"),
                     (findData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? _T('A') : _T(' '),
                     (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? _T('S') : _T(' '),
                     (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? _T('H') : _T(' '),
                     (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? _T('R') : _T(' '),
                     szFullName);
    }
    while (FindNextFile(hFind, &findData));
    FindClose(hFind);
}


static VOID
ChangeAttribute(LPTSTR pszPath, LPTSTR pszFile, DWORD dwMask,
                DWORD dwAttrib, BOOL bRecurse, BOOL bDirectories)
{
    WIN32_FIND_DATA findData;
    HANDLE hFind;
    DWORD  dwAttribute;
    TCHAR  szFullName[MAX_PATH];
    LPTSTR pszFileName;


    /* prepare full file name buffer */
    _tcscpy (szFullName, pszPath);
    pszFileName = szFullName + _tcslen (szFullName);

    /* change all subdirectories */
    if (bRecurse)
    {
        /* append file name */
        _tcscpy (pszFileName, _T("*.*"));

        hFind = FindFirstFile (szFullName, &findData);
        if (hFind == INVALID_HANDLE_VALUE)
        {
            ErrorMessage (GetLastError (), pszFile);
      nErrorLevel = 1;
            return;
        }

        do
        {
            if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                if (!_tcscmp (findData.cFileName, _T(".")) ||
                    !_tcscmp (findData.cFileName, _T("..")))
                    continue;

                _tcscpy (pszFileName, findData.cFileName);
                _tcscat (pszFileName, _T("\\"));

                ChangeAttribute (szFullName, pszFile, dwMask,
                                 dwAttrib, bRecurse, bDirectories);
            }
        }
        while (FindNextFile (hFind, &findData));
        FindClose (hFind);
    }

    /* append file name */
    _tcscpy (pszFileName, pszFile);

    hFind = FindFirstFile (szFullName, &findData);
    if (hFind == INVALID_HANDLE_VALUE)
    {
        ErrorMessage (GetLastError (), pszFile);
    nErrorLevel = 1;
        return;
    }

    do
    {
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            continue;

        _tcscpy (pszFileName, findData.cFileName);

        dwAttribute = GetFileAttributes (szFullName);

        if (dwAttribute != 0xFFFFFFFF)
        {
            dwAttribute = (dwAttribute & ~dwMask) | dwAttrib;
            SetFileAttributes (szFullName, dwAttribute);
        }
    }
    while (FindNextFile (hFind, &findData));
    FindClose (hFind);
}


INT CommandAttrib (LPTSTR param)
{
    LPTSTR *arg;
    INT    argc, i;
    TCHAR  szPath[MAX_PATH];
    TCHAR  szFileName [MAX_PATH];
    BOOL   bRecurse = FALSE;
    BOOL   bDirectories = FALSE;
    DWORD  dwAttrib = 0;
    DWORD  dwMask = 0;

    /* initialize strings */
    szPath[0] = _T('\0');
    szFileName[0] = _T('\0');

    /* print help */
    if (!_tcsncmp (param, _T("/?"), 2))
    {
        ConOutResPaging(TRUE,STRING_ATTRIB_HELP);
        return 0;
    }

    nErrorLevel = 0;

    /* build parameter array */
    arg = split (param, &argc, FALSE, FALSE);

    /* check for options */
    for (i = 0; i < argc; i++)
    {
        if (_tcsicmp (arg[i], _T("/s")) == 0)
            bRecurse = TRUE;
        else if (_tcsicmp (arg[i], _T("/d")) == 0)
            bDirectories = TRUE;
    }

    /* create attributes and mask */
    for (i = 0; i < argc; i++)
    {
        if (*arg[i] == _T('+'))
        {
            if (_tcslen (arg[i]) != 2)
            {
                error_invalid_parameter_format (arg[i]);
                freep (arg);
                return -1;
            }

            switch ((TCHAR)_totupper (arg[i][1]))
            {
                case _T('A'):
                    dwMask   |= FILE_ATTRIBUTE_ARCHIVE;
                    dwAttrib |= FILE_ATTRIBUTE_ARCHIVE;
                    break;

                case _T('H'):
                    dwMask   |= FILE_ATTRIBUTE_HIDDEN;
                    dwAttrib |= FILE_ATTRIBUTE_HIDDEN;
                    break;

                case _T('R'):
                    dwMask   |= FILE_ATTRIBUTE_READONLY;
                    dwAttrib |= FILE_ATTRIBUTE_READONLY;
                    break;

                case _T('S'):
                    dwMask   |= FILE_ATTRIBUTE_SYSTEM;
                    dwAttrib |= FILE_ATTRIBUTE_SYSTEM;
                    break;

                default:
                    error_invalid_parameter_format (arg[i]);
                    freep (arg);
                    return -1;
            }
        }
        else if (*arg[i] == _T('-'))
        {
            if (_tcslen (arg[i]) != 2)
            {
                error_invalid_parameter_format (arg[i]);
                freep (arg);
                return -1;
            }

            switch ((TCHAR)_totupper (arg[i][1]))
            {
                case _T('A'):
                    dwMask   |= FILE_ATTRIBUTE_ARCHIVE;
                    dwAttrib &= ~FILE_ATTRIBUTE_ARCHIVE;
                    break;

                case _T('H'):
                    dwMask   |= FILE_ATTRIBUTE_HIDDEN;
                    dwAttrib &= ~FILE_ATTRIBUTE_HIDDEN;
                    break;

                case _T('R'):
                    dwMask   |= FILE_ATTRIBUTE_READONLY;
                    dwAttrib &= ~FILE_ATTRIBUTE_READONLY;
                    break;

                case _T('S'):
                    dwMask   |= FILE_ATTRIBUTE_SYSTEM;
                    dwAttrib &= ~FILE_ATTRIBUTE_SYSTEM;
                    break;

                default:
                    error_invalid_parameter_format (arg[i]);
                    freep (arg);
                    return -1;
            }
        }
    }

    if (argc == 0)
    {
        DWORD len;

        len = GetCurrentDirectory (MAX_PATH, szPath);
        if (szPath[len-1] != _T('\\'))
        {
            szPath[len] = _T('\\');
            szPath[len + 1] = 0;
        }
        _tcscpy (szFileName, _T("*.*"));
        PrintAttribute (szPath, szFileName, bRecurse);
        freep (arg);
        return 0;
    }

    /* get full file name */
    for (i = 0; i < argc; i++)
    {
        if ((*arg[i] != _T('+')) && (*arg[i] != _T('-')) && (*arg[i] != _T('/')))
        {
            LPTSTR p;
            GetFullPathName (arg[i], MAX_PATH, szPath, NULL);
            p = _tcsrchr (szPath, _T('\\')) + 1;
            _tcscpy (szFileName, p);
            *p = _T('\0');

            if (dwMask == 0)
                PrintAttribute (szPath, szFileName, bRecurse);
            else
                ChangeAttribute (szPath, szFileName, dwMask,
                         dwAttrib, bRecurse, bDirectories);
        }
    }

    freep (arg);
    return 0;
}

#endif /* INCLUDE_CMD_ATTRIB */