A Simple ls Program

Posted on by on May 1st, 2013 | 0 Comments ยป
////////////////////////////////////////////////////////////////////////////////
/**
 *  @file ls_01.c
 *  @brief Write a program in C that is similar to the ls command.
 *
 *  @title ls 01
 *  @author Nicholas Guthrie
 *  @web http//nickguthrie.com
 *  @created February 4, 2013
 *
 *  Compile with: gcc -g -Wall -o ./ls_01 ls_01.c
 */
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------ :Libraries:
//                      _    _ _                 _
//                     | |  (_) |__ _ _ __ _ _ _(_)___ ___
//                     | |__| | '_ \ '_/ _` | '_| / -_|_-<
//                     |____|_|_.__/_| \__,_|_| |_\___/__/
//
// -----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <limits.h> /* limits.h defines "PATH_MAX". */
#include <sys/stat.h>
//----------------------------------------------------------------- :Prototypes:
//                  ___         _       _
//                 | _ \_ _ ___| |_ ___| |_ _  _ _ __  ___ ___
//                 |  _/ '_/ _ \  _/ _ \  _| || | '_ \/ -_|_-<
//                 |_| |_| \___/\__\___/\__|\_, | .__/\___/__/
//                                          |__/|_|
//
//-----------------------------------------------------------------------------
int o_dir(char * dir, int level, char * f_name);
void get_permissions (char *mode, unsigned int imode);
/**----------------------------------------------------------------------- :Main:
//                              __  __      _
//                             |  \/  |__ _(_)_ _
//                             | |\/| / _` | | ' \
//                             |_|  |_\__,_|_|_||_|
//
-----------------------------------------------------------------------------*/
int main( int argc, char *argv[] )
{
    char d_name[3] = ".";     /* initial directory */

    //Debug - cleaner way of formatting pointers?
    char * p_name = d_name;
    char * pf_name = NULL;

    //Obtain Argument
    if ( argc == 2 ) /* argc should be 2 for correct execution */
    {
        //printf( "Argument is %s\n", argv[1] );
	pf_name = argv[1];
	//strcpy(f_name, argv[1]);
    }
    // Error Checking for > 1 Argument
    if ( argc > 2 )
    {
	printf( "Usage: %s (optional)filename\nExiting.\n", argv[0] );
	return -1;
    }


    o_dir(p_name, 0, pf_name);
    return EXIT_SUCCESS;
}
//------------------------------------------------------------------ :Functions:
//                      ___             _   _
//                     | __|  _ _ _  __| |_(_)___ _ _  ___
//                     | _| || | ' \/ _|  _| / _ \ ' \(_-<
//                     |_| \_,_|_||_\__|\__|_\___/_||_/__/
//
//
//-----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/**
 *  @brief Recursively search for directories.
 *  @param[in] c_dir The name of the directory to search.
 *  @param[in] level Used to keep track of spacing for sub-directories.
 *  @return EXIT_SUCCESS if successful
 */
////////////////////////////////////////////////////////////////////////////////
int o_dir( char * c_dir, int level, char * f_name )
{
    DIR * dir = opendir(c_dir);
    struct dirent * file;
    while ( ( file = readdir( dir ) ) != NULL )
    {
	// check for dir open failure
	if ( dir == NULL )
	{
	    perror( "opendir() failed\n" );
	    return EXIT_FAILURE;
	}
	// Read File Info
	    struct stat buf;
	    int rc = lstat( file->d_name, &buf );
	// check for . or .. as first char in name
	if ( (strcmp (file->d_name, "..") != 0 && strcmp (file->d_name, ".") != 0) &&
	     ( S_ISDIR(buf.st_mode) || ( S_ISREG( buf.st_mode )
		&& (f_name == NULL || strcmp(f_name, file->d_name) == 0))))
	{
	    //Print Directory Level Spacing
	    int i;
	    for(i=0; i<level*4;i++)
		printf(" ");

	    //@DEBUG - What is this used for?
	    if ( rc < 0 )
	    {
	    	 /* perror( "lstat() failed\n" );  */
		 /* return EXIT_FAILURE;  */
	    }
	    else
	    {
		printf( "%s ", file->d_name);
		if ( S_ISDIR( buf.st_mode ) )
		{

		    char rwx_perms[12];
		    get_permissions (rwx_perms, buf.st_mode);
		    printf( "(subdirectory) [%s]\n",  rwx_perms);
		    // Recursive Section
		    int path_length;
		    char path[PATH_MAX];
		    path_length = snprintf (path, PATH_MAX,
					    "%s/%s", c_dir, file->d_name);
		    //Check Path Length
		    if (path_length >= PATH_MAX)
		    {
		    	fprintf (stderr, "Path length has got too long.\n");
		    	exit (EXIT_FAILURE);
		    }
		    //Recursively call with the new path.
		    chdir(file->d_name);
		    o_dir (".", level + 1, f_name);
		    chdir("..");
		}
		// Regular File
		else if ( S_ISREG(buf.st_mode) )
		{
		    //Determine rwx_perms
		    char rwx_perms[12];
		    get_permissions (rwx_perms, buf.st_mode);
		    printf( "(%d bytes) [%s]\n", (int) buf.st_size, rwx_perms);
		}
		// Sub-Directory
		// System Link
		/*else if ( S_ISLNK( buf.st_mode ) )
		{
		    printf( "[symbolic link]\n" );
		    }*/
		// Unknown File
		/* else */
		/* { */
		/*     //Do Nothing */
		/* } */
	    }
	}
    }
    closedir( dir );
    return EXIT_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////
/**
 *  @brief Given the octal permission of a file, determine rwx human readable
 *  @param[out] mode Stores the string of rwx permissions.
 *  @param[in] imode
 *  @return void. Results stored in *mode.
 */
////////////////////////////////////////////////////////////////////////////////
void get_permissions (char *mode, unsigned int imode )
{
    int i[16];
    int count=0;
    int rem;
    memset( i,0,16 );
    memset( mode,'\0',11 );

    /*Convert to binary*/
    while ( imode>0 )
    {
	rem=imode%2;
	imode/=2;
	i[count]=rem;
	count++;
    }
    /*End Binary Coversion*/
    count=0;

    /*Start Processing bits*/
    int j;
    for ( j=15;j>=0;j-- )
    {
	switch ( j )
	{
	case 15 :   if ( i[j]==1 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='d';
		count++;
	    }
	    break;
	case  8 :   if ( i[j]==0 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='r';
		count++;
	    }
	    break;
	case  7 :   if ( i[j]==0 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='w';
		count++;
	    }
	    break;
	case  6 :   if ( i[j]==0 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='x';
		count++;
	    }
	    break;
	case  5 :   if ( i[j]==0 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='r';
		count++;
	    }
	    break;
	case  4 :   if ( i[j]==0 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='w';
		count++;
	    }
	    break;
	case  3 :   if ( i[j]==0 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='x';
		count++;
	    }
	    break;
	case  2 :   if ( i[j]==0 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='r';
		count++;
	    }
	    break;
	case  1 :   if ( i[j]==0 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='w';
		count++;
	    }
	    break;
	case  0 :   if ( i[j]==0 )
	    {
		mode[count]='-';
		count++;
	    } else {
		mode[count]='x';
		count++;
	    }
	    break;
	}
    }
}
Manlier Word Game
A Simple SHELL Program

Categorized Under

CLanguagesProgramming

About Nick Guthrie

» has written 38 posts

History