O how well I remember DOS. It wasn’t Unix, but it cribbed from Unix heavily. One of the popular DOS commands was DIR
, which was like the shell command ls, but more primitive. A typical DOS directory listing looked something like this:
Volume in drive C is TOO LOUD Directory of C:\PROG\C . <DIR> .. <DIR> 0901a c 383 8-18-18 9:42p 0901b c 506 8-19-18 12:13p 0908 c 796 8-25-18 11:24a 0915 c 44 8-04-18 3:27p a out 8940 8-25-18 11:24a gettys~1 txt 177 9-05-15 9:59a sto <DIR> 6 File(s) bytes free
The filename came first, split into the 8-character name and 3-character extension. Then came the file’s size, or <DIR>
for a directory, followed by the date and time stamp. The cmd shell in Windows displays the filename last because the original 8-dot-3 format was discarded long ago; the original format is shown above.
To imitate this format in C, you must extract each filename in the directory, its size, timestamp, and determine whether the file is a directory. From last week’s Lesson, I demonstrated how to use the stat() function and S_ISDIR
macro to pull out directory entries. The two other tidbits required for a DOS-like directory listing are the file’s size and its timestamp. Both of these items can be pulled from structure returned from the stat() function.
A file’s size is located in the stat
structure’s st_size
member.
The stat
structure has three members that deal with timestamps:
st_atime
, which returns when file data was last accessed
st_mtime
, which returns when the file’s data was last modified
st_ctime
, which returns when the file’s status was changed
A fourth member, st_birthtime
, returns when the file was created, though this member isn’t available to all operating systems.
You can read more about these fields from my March 24 2018 Lesson here.
The following code represents my attempt to ape the old DOS directory command output. I didn’t bother splitting the filenames between name and extension or cropping long filenames. And I don’t use the exact format for the timestamp as it would be a bother to extract.
#include <stdio.h> #include <dirent.h> #include <sys/stat.h> #include <unistd.h> #include <time.h> int main() { DIR *folder; struct dirent *entry; struct stat filestat; char cwdpath[256]; int count = 1; long long total = 0; folder = opendir("."); if(folder == NULL) { perror("Unable to read directory"); return(1); } /* State directory name */ getcwd(cwdpath,256); printf(" Directory of %s\n\n",cwdpath); /* Read directory entries */ while( (entry=readdir(folder)) ) { /* Extract Filename */ stat(entry->d_name,&filestat); printf("%-16s",entry->d_name); /* Extract Size */ if( S_ISDIR(filestat.st_mode) ) printf("%-8s ","<DIR>"); else { printf("%8lld ",filestat.st_size); total+=filestat.st_size; } /* Extract create date and time */ printf("%s",ctime(&filestat.st_mtime)); } closedir(folder); printf("\n %d File(s) for %lld bytes\n", count, total ); return(0); }
For each directory entry read, the stat() function fills the filestat
structure. The file’s full name is displayed at Line 32. I used a left-justified string output buffer with the placeholder %-16s
. The 16-character width might be too narrow for some longer filenames.
The filestat.st_mode
member and S_ISDIR
macro help pull out directories. Unlike last week’s example, for a regular file, the filestat.st_size
member helps read the file’s size in bytes. This member is typecast as a off_t variable, which translates into a long long integer and uses the %lld
placeholder.
The date and time stamp is pulled at Line 44, which is similar to examples in my blog post cited previously in this Lesson.
Here’s sample output:
Directory of /Users/dang/prog/c/blog . <DIR> Sat Aug 25 12:07:13 2018 .. <DIR> Sun Aug 5 19:40:28 2018 0901a.c 383 Sat Aug 18 21:42:04 2018 0901b.c 506 Sun Aug 19 12:13:32 2018 0908.c 954 Sat Aug 25 12:07:08 2018 0915.c 44 Sat Aug 4 15:27:24 2018 a.out 8940 Sat Aug 25 12:07:13 2018 gettysburg.txt 177 Sat Sep 5 08:59:18 2015 sto <DIR> Sat Feb 25 08:06:17 2017 9 File(s) for 11004 bytes
In next week’s Lesson, I explore recursively spelunking a directory structure.