home *** CD-ROM | disk | FTP | other *** search
- // ls - Windows NT directory listing utility
- //
- // Author: Jon S. Whalen (c) 1993
- // internet: jon@hook.corp.mot.com
- // compuserve: 76665,3043
- //
- // 6 March 1993
- // Release 1.0 'ls.exe'
-
- #include <windef.h>
- #include <excpt.h>
- #include <winbase.h>
- #include <iostream.h>
- #include <stdlib.h>
- #include <winuser.h>
- //#include <wincon.h>
-
- // the structs and functions are declared in
- // wincon.h, but not for C++, so they're included here to get
- // the linkage to work.
-
- typedef struct _COORD {
- SHORT X;
- SHORT Y;
- } COORD, *PCOORD;
-
- typedef struct _SMALL_RECT {
- SHORT Left;
- SHORT Top;
- SHORT Right;
- SHORT Bottom;
- } SMALL_RECT, *PSMALL_RECT;
-
- typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
- COORD dwSize;
- COORD dwCursorPosition;
- WORD wAttributes;
- SMALL_RECT srWindow;
- COORD dwMaximumWindowSize;
- } CONSOLE_SCREEN_BUFFER_INFO, *PCONSOLE_SCREEN_BUFFER_INFO;
-
- extern "C" BOOL WINAPI GetConsoleScreenBufferInfo( HANDLE, PCONSOLE_SCREEN_BUFFER_INFO );
- extern "C" BOOL WINAPI SetConsoleCursorPosition( HANDLE, COORD );
-
- // error/usage message
-
- void Usage( void )
- {
- cerr << "\nProgram: \"ls.exe\" - Windows NT directory list utility - Version 1.0" << endl;
- cerr << " Copyright (c) Jon S. Whalen 1993. All rights reserved." << endl;
- cerr << "\nusage: ls [-1?alstzLSTFZ] [path|file|pattern]\n" << endl;
- cerr << " ?|h: display this usage message" << endl;
- cerr << " 1: format as single column, left adjusted" << endl;
- cerr << " a: show all files (including .* and hidden files)" << endl;
- cerr << " F: add suffixes to the file names:" << endl;
- cerr << " '\\' = directory" << endl;
- cerr << " '!' = hidden file (only when -a is specified)" << endl;
- cerr << " '&' = system file" << endl;
- cerr << " l: use long listing format" << endl;
- cerr << " L: use longer listing format" << endl;
- cerr << " s: sort by size - decreasing" << endl;
- cerr << " S: sort by size - increasing" << endl;
- cerr << " t: sort by modification time - newest first" << endl;
- cerr << " T: sort by modification time - oldest first" << endl;
- cerr << " z: sort by name - lexical order (i.e. alphabetical order)" << endl;
- cerr << " Z: sort by name - reverse lexical order" << endl;
- cerr << "\nNotes:\n" << endl;
- cerr << " 1. For compatibility with Unix ls, file and directory names beginning" << endl;
- cerr << " with '.' are not displayed unless the -a option is specified." << endl;
- cerr << " 2. Specifiying only a drive name (e.g. \"ls C:\") will list the contents" << endl;
- cerr << " of the current working directory for that drive." << endl;
- cerr << " 3. File systems which are case-insensitive (e.g. FAT) are displayed" << endl;
- cerr << " in lower case. Case-sensitive file systems (e.g. NTFS) are displayed" << endl;
- cerr << " in mixed upper and lower case. It is Unicode compatible." << endl;
- cerr << " 4. This program is freely distributable and is provided \"AS-IS\", WITHOUT" << endl;
- cerr << " WARRANTY of any kind, either express or implied. No guarantee is made" << endl;
- cerr << " of suitablility for any purpose, whatsoever." << endl;
- }
-
- struct FileListEl {
- WIN32_FIND_DATA *lpwfd;
- FileListEl *next, *prev;
- FileListEl( void ) : lpwfd(0), next(0), prev(0) { }
- ~FileListEl( void ) { if( lpwfd ) delete lpwfd; }
- };
-
- void SwapEl( FileListEl * cur, FileListEl *next )
- {
- FileListEl * p1 = (cur?cur->prev:0);
- FileListEl * p2 = cur;
- FileListEl * p3 = next;
- FileListEl * p4 = (p3?p3->next:0);
-
- if( p1 ) p1->next = p3;
- p3->prev = p1;
- if( p4 ) p4->prev = p2;
- p2->next = p4;
- p3->next = p2;
- p2->prev = p3;
- }
-
- int GetFileList( TCHAR * filter, FileListEl *& head, DWORD & max_filename_len )
- {
- FileListEl * cur = 0;
- WIN32_FIND_DATA * lpwfd;
- int matches = 0;
- DWORD len = 0;
-
- lpwfd = new WIN32_FIND_DATA;
- HANDLE hSearch = FindFirstFile( filter, lpwfd );
- if( hSearch == INVALID_HANDLE_VALUE )
- {
- return 0;
- }
-
- // else
- cur = head = new FileListEl;
- head->lpwfd = lpwfd;
- max_filename_len = lstrlen(lpwfd->cFileName);
- matches = 1;
-
- lpwfd = new WIN32_FIND_DATA;
- while( FindNextFile( hSearch, lpwfd ) )
- {
- cur->next = new FileListEl; cur->next->prev = cur; cur = cur->next;
- cur->lpwfd = lpwfd;
-
- len = lstrlen(lpwfd->cFileName);
- if( max_filename_len < len ) max_filename_len = len;
-
- lpwfd = new WIN32_FIND_DATA;
- matches++;
- }
- delete lpwfd;
-
- FindClose( hSearch );
-
- return matches;
- }
-
- int main( int argc, TCHAR **argv )
- {
- CONSOLE_SCREEN_BUFFER_INFO csbi;
- TIME_ZONE_INFORMATION tzi;
-
- TCHAR filter[512]; filter[0] = 0;
- TCHAR cur_directory[512]; cur_directory[0] = 0;
- TCHAR new_directory[512]; new_directory[0] = 0;
- TCHAR * cp = 0;
-
- DWORD len = 0;
- DWORD maxlen = 512;
- DWORD max_filename_len = 0;
- LPTSTR progname = argv[0];
- FileListEl * head = 0;
- FileListEl * cur = 0;
- DWORD pos = 0;
- int column = 0;
- int num_columns = 0;
-
- // Flags
-
- int f_list_all = 0;
- int f_long_list = 0;
- int f_modify_time_sort = 0;
- int f_alpha_sort = 1;
- int f_size_sort = 0;
- int f_list_with_suffix = 0;
- int f_single_column = 0;
-
- int error = 0;
- int suffixed = 0;
- int case_sensitive = 0;
- int matches = 0;
- long result = 0;
-
- // open a handle to the console
-
- HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-
- // check out the environment
-
- result = GetCurrentDirectory( maxlen, cur_directory );
- result = GetConsoleScreenBufferInfo(hOutput, &csbi);
- result = GetTimeZoneInformation(&tzi);
-
- DWORD line_length = csbi.dwSize.X;
-
- // process command line args
-
- argc--; argv++; // skip progname
- for ( ; argc && ((*argv)[0] == L'/' || (*argv)[0] == L'-'); argv++, argc-- )
- {
- cp = *argv; cp++;
- while( *cp )
- {
- switch( *cp )
- {
- case L'h':
- case L'?':
- Usage();
- return -1;
- break;
- case L'1':
- f_single_column++;
- break;
- case L'a':
- f_list_all++;
- break;
- case L'l':
- f_long_list = 1;
- break;
- case L'L':
- f_long_list = 2;
- break;
- case L's':
- f_size_sort = 1;
- f_alpha_sort = 0;
- f_modify_time_sort = 0;
- break;
- case L'S':
- f_size_sort = -1;
- f_alpha_sort = 0;
- f_modify_time_sort = 0;
- break;
- case L't':
- f_modify_time_sort = 1;
- f_alpha_sort = 0;
- f_size_sort = 0;
- break;
- case L'T':
- f_modify_time_sort = -1;
- f_alpha_sort = 0;
- f_size_sort = 0;
- break;
- case L'F':
- f_list_with_suffix++;
- break;
- case L'z':
- f_alpha_sort = 1;
- f_modify_time_sort = 0;
- f_size_sort = 0;
- break;
- case L'Z':
- f_alpha_sort = -1;
- f_modify_time_sort = 0;
- f_size_sort = 0;
- break;
- default:
- cerr << "ls: illegal option -- " << *cp << endl;
- error++;
- }
- cp++;
- }
- }
-
- if( error )
- {
- Usage( );
- return -1;
- }
-
- if( argc == 0 )
- {
- filter[0] = L'*';
- filter[1] = L'.';
- filter[2] = L'*';
- filter[3] = 0;
- }
- else
- {
- // check to see if the argument specifies a path
-
- lstrcpy( filter, *argv );
- long index = lstrlen( filter );
- switch( filter[index - 1] )
- {
- case L':':
- case L'\\':
- filter[index] = L'*';
- filter[index + 1] = L'.';
- filter[index + 2] = L'*';
- filter[index + 3] = 0;
- break;
- }
-
- }
-
- // get drive information
-
- DWORD dwMaxFilename, dwFlags;
- TCHAR file_system_name[32];
- TCHAR volume_name[128];
- DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
- DWORD free_bytes, total_bytes;
-
- if( filter[1] == L':' )
- {
- TCHAR tmp[4];
- tmp[0] = filter[0]; tmp[1] = filter[1]; tmp[2] = L'\\'; tmp[3] = 0;
- GetVolumeInformation( tmp, volume_name, 128, 0, &dwMaxFilename, &dwFlags, file_system_name, 32 );
- GetDiskFreeSpace( tmp, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
- }
- else
- {
- GetVolumeInformation( 0, volume_name, 128, 0, &dwMaxFilename, &dwFlags, file_system_name, 32 );
- GetDiskFreeSpace( 0, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
- }
-
- if( dwFlags & FS_CASE_IS_PRESERVED )
- case_sensitive++;
- total_bytes = total_clusters * sectors_per_cluster * bytes_per_sector;
- free_bytes = free_clusters * sectors_per_cluster * bytes_per_sector;
-
- // first find all matching files
-
- matches = GetFileList( filter, head, max_filename_len );
- if( !matches )
- {
- cout << filter << " not found." << endl;
- return 0;
- }
- else if( matches == 1 && (head->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) )
- {
- delete head; head = 0;
-
- // the filter was a directory name, add \*.* to the filter
-
- long index = lstrlen( filter );
- filter[index] = L'\\';
- filter[index + 1] = L'*';
- filter[index + 2] = L'.';
- filter[index + 3] = L'*';
- filter[index + 4] = 0;
-
- // now try again
-
- matches = GetFileList( filter, head, max_filename_len );
- }
-
- if( f_single_column )
- num_columns = 1;
- else
- num_columns = line_length/(max_filename_len + 4);
-
- // now sort
-
- if( f_modify_time_sort )
- {
- // this is a dumb sorting algorithm -- I'll replace it soon?
- int swapped_one = 1;
-
- while( swapped_one )
- {
- swapped_one = 0;
- for( cur = head; cur && cur->next; cur = cur->next )
- {
- result = CompareFileTime( &(cur->lpwfd->ftLastWriteTime), &(cur->next->lpwfd->ftLastWriteTime) );
-
- if( f_modify_time_sort < 0 ) result *= -1;
-
- if( result == -1 )
- {
- // swap the entries
- swapped_one++;
- FileListEl * next = cur->next;
- SwapEl( cur, next );
- if( head == cur ) head = next;
- cur = next;
- }
- }
- }
- }
- else if( f_size_sort )
- {
- // this is a dumb sorting algorithm -- I'll replace it soon?
- int swapped_one = 1;
-
- while( swapped_one )
- {
- swapped_one = 0;
- for( cur = head; cur && cur->next; cur = cur->next )
- {
- if( (cur->lpwfd->nFileSizeLow) < (cur->next->lpwfd->nFileSizeLow) )
- result = -1;
- else if ( (cur->next->lpwfd->nFileSizeLow) == (cur->lpwfd->nFileSizeLow) )
- result = 0;
- else
- result = 1;
-
- if( f_size_sort < 0 ) result *= -1;
-
- if( result == -1 )
- {
- // swap the entries
- swapped_one++;
- FileListEl * next = cur->next;
- SwapEl( cur, next );
- if( head == cur ) head = next;
- cur = next;
- }
- }
- }
- }
- else if( f_alpha_sort )
- {
- // this is a dumb sorting algorithm -- I'll replace it soon?
- int swapped_one = 1;
-
- while( swapped_one )
- {
- swapped_one = 0;
- for( cur = head; cur && cur->next; cur = cur->next )
- {
- result = lstrcmp( (cur->next->lpwfd->cFileName), (cur->lpwfd->cFileName) );
-
- if( f_alpha_sort < 0 ) result *= -1;
-
- if( result == -1 )
- {
- // swap the entries
- swapped_one++;
- FileListEl * next = cur->next;
- SwapEl( cur, next );
- if( head == cur ) head = next;
- cur = next;
- }
- }
- }
- }
-
- // print the listing
-
- if ( f_long_list )
- {
- if( f_long_list > 1 )
- {
- cout << "\nVolume Name: \"" << volume_name << "\" File System Type: [" << file_system_name << "]" << endl;
- cout << "\n[Attribs] [Size] [Created] [Last Modified] [Name]" << endl;
- }
- else
- cout << "\n[Attribs] [Size] [Last Modified] [Name]" << endl;
-
- for( cur = head; cur; cur = cur->next )
- {
- if ( f_list_all || (cur->lpwfd->cFileName[0] != L'.' && !(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)) )
- {
- SYSTEMTIME stm;
- TCHAR buffer[128];
-
- // attributes
-
- cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) ? 'd':'-');
- cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) ? 'h':'-');
- cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_SYSTEM) ? 's':'-');
- cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_READONLY) ? 'r':'-');
- cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_ARCHIVE) ? 'a':'-');
-
- // attributes for NTFS only
-
- cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_TEMPORARY) ? 't':'-');
- cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_ATOMIC_WRITE) ? 'm':'-');
- cout << (CHAR)((cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_XACTION_WRITE) ? 'x':'-');
- cout << " ";
-
- // size
-
- wsprintf( buffer, "%wc%9d ", ((cur->lpwfd->nFileSizeHigh)?L'+':L' '), cur->lpwfd->nFileSizeLow );
- cout << buffer;
-
- if( f_long_list > 1 )
- {
- // creation time
-
- FileTimeToSystemTime( &(cur->lpwfd->ftCreationTime), &stm);
- wsprintf( buffer, " %02d-%02d-%02d %02d:%02d:%02d ", stm.wMonth, stm.wDay, (stm.wYear%100), (stm.wHour - tzi.Bias/60), stm.wMinute, stm.wSecond );
- cout << buffer;
-
- // last access time
-
- //FileTimeToSystemTime( &(cur->lpwfd->ftLastAccessTime), &stm);
- //wsprintf( buffer, " %02d-%02d-%02d %02d:%02d:%02d ", stm.wMonth, stm.wDay, (stm.wYear%100), (stm.wHour - tzi.Bias/60), stm.wMinute, stm.wSecond );
- //cout << buffer;
- }
-
- // last modification time
-
- FileTimeToSystemTime( &(cur->lpwfd->ftLastWriteTime), &stm);
- wsprintf( buffer, " %02d-%02d-%02d %02d:%02d:%02d ", stm.wMonth, stm.wDay, (stm.wYear%100), (stm.wHour - tzi.Bias/60), stm.wMinute, stm.wSecond );
- cout << buffer;
-
- cout << (case_sensitive?cur->lpwfd->cFileName:CharLower(cur->lpwfd->cFileName));
- if( f_list_with_suffix )
- {
- if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
- cout << L'\\';
- else
- {
- if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)
- cout << L'!';
- if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_SYSTEM)
- cout << L'&';
- }
- }
- cout << endl;
- }
- }
-
- if( f_long_list > 1 )
- {
- cout << "\nVolume Statistics:" << endl;
- cout << "\n[Size] " << total_bytes << " [Free] " << free_bytes <<" [% Used] " << 100.00*(long)(total_bytes - free_bytes)/(long)total_bytes << "." << endl;
- //cout << "bytes used: " << (total_bytes - free_bytes) endl;
- }
- } // end-if
-
- else
- for( cur = head; cur; cur = cur->next )
- {
- if ( f_list_all || (cur->lpwfd->cFileName[0] != L'.' && !(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)) )
- {
- len = lstrlen(cur->lpwfd->cFileName);
- if( column == num_columns )
- {
- cout << endl;
- column = 1;
- }
- else
- column++;
-
- // filename
-
- cout << (case_sensitive?cur->lpwfd->cFileName:CharLower(cur->lpwfd->cFileName));
- pos += len;
-
- // suffix
-
- suffixed = 0;
- if( f_list_with_suffix )
- {
- if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
- {
- cout << L'\\';
- suffixed++;
- }
- else
- {
- if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)
- {
- cout << L'!';
- suffixed++;
- }
- if(cur->lpwfd->dwFileAttributes&FILE_ATTRIBUTE_SYSTEM)
- {
- cout << L'&';
- suffixed++;
- }
- }
- pos++;
- }
-
- // padding
-
- len = max_filename_len - len + 4 - suffixed;
- if( column < num_columns )
- while( len-- ) cout << ' ';
- }
- }
-
- return 0;
- }
-