Jump to content

ls clone

- - - - -

  • Please log in to reply
No replies to this topic

#1
DarkLordofthePenguins

DarkLordofthePenguins

    Programming Expert

  • Members
  • PipPipPipPipPipPip
  • 409 posts
Here is a clone I wrote for the ls command in Unix. It's a work in progress, because I haven't implemented the file type options, and I don't have user and group IDs. It allows the user to specify how many columns to print, whether to print file size, whether to print in long format, whether to print dot files, and whether to show colors. I used POSIX filesystem functions and some bit magic to get it to work efficiently.


// A clone of ls

// Still unfinished


#include <stdio.h>

#include <string.h>

#include <unistd.h>

#include <dirent.h>

#include <sys/stat.h>


unsigned char flags = 0;

// 1: -a, 2: -l, 4: -G, 8: -s, 16: -t

unsigned char tflags = 0;

// 1: on, 2: reg, 4: dir, 8: lin, 16: dev


void printfile( struct dirent * );


int main( int argc, char **argv ){

	char *dirname;

	int cols = 3;


	// Parse command line parameters

	for( int i = 1; i < argc; i++ ){

		if( tflags & 0x1 ){

			// Type options not implemented yet

			switch( argv[i][0] ){

				case 'f' : tflags |= 0x2;

				           break;

				case 'd' : tflags |= 0x4;

				           break;

				case 'l' : tflags |= 0x8;

				           break;

				case 'v' : tflags |= 0x10;

				           break;

				default  : tflags |= 0x1e;

			}

			tflags--;

		}

		if( argv[i][0] == '-' ){

			int optlen = strlen( argv[i] );

			printf( "%d\n", optlen );

			for( int j = 1; j < optlen; j++ ){

				if( argv[i][j] > 0x30 && argv[i][j] < 0x40 ){

				// Number of columns

					cols = argv[i][j] - 0x30;

				}

				else if( argv[i][j] == 'a' ){

				// List all files

					flags |= 0x1;

				}

				else if( argv[i][j] == 'l' ){

				// List files in long format

					flags |= 0x2;

					cols = 1;

				}

				else if( argv[i][j] == 'G' ){

				// List files with color

					flags |= 0x4;

				}

				else if( argv[i][j] == 's' ){

				// Show file sizes

					flags |= 0x8;

					cols = 1;

				}

				else if( argv[i][j] == 't' ){

				// List by type

					tflags |= 0x1;

					cols = 1;

				}

			}

		}

		else{

			dirname = argv[i];

		}

	}

	// End parse parameters


	chdir( dirname );

	char buf[256];

	DIR *dp = opendir( getcwd( buf, 256 ) );

	struct dirent *entry;


	if( cols < 1 ){

		closedir( dp );

		return 0;

	}


	else if( cols > 1 ){

		int counter = 0;

		while( (entry = readdir( dp )) != NULL ){

			if( (flags & 0x1) == 0 ){

			// if -a is not set

				if( entry->d_name[0] != '.' ){

				// Only print if not a dot file

					printfile( entry );

					if( ++counter % cols == 0 ){

					// newline after counter times

						putchar( '\n' );

					}

				}

			}

			else{

			// if -a is set print unconditionally

				printfile( entry );

				if( ++counter % cols == 0 ){

					putchar( '\n' );

				}

			}

		}

		if( counter % cols != 0 ){

			putchar( '\n' );

		}

	}


	else{

		while( (entry = readdir( dp )) != NULL ){

			if( (flags & 0x1) || (entry->d_name[0] != '.') ){

				printfile( entry );

				putchar( '\n' );

			}

		}

	}

	return 0;

}


void printfile( struct dirent *entry ){

	struct stat inode;

	lstat( entry->d_name, &inode );

	int ftype = inode.st_mode;

	int acmod = inode.st_mode;

	ftype >>= 9;

	acmod &= 0777;

	// Least significant nine bits are the access mode

	if( (flags & 0x2 ) ){ // If -l

		// Print file type:

		switch( ftype ){

			case 0100 : putchar( '-' );

			// Regular file

			            break;

			case 040  : putchar( 'd' );

			// Directory

			            break;

			case 0120 : putchar( 'l' );

			// Symbolic link

			            break;

			case 010  : putchar( 'p' );

			// Named pipe

			            break;

			case 060  : putchar( 'b' );

			// Block special file

			            break;

			case 020  : putchar( 'c' );

			// Character special file

			            break;

			case 016  : putchar( 'b' );

			// Block file

			            break;

			default   : putchar( '?' );

		}

		// Print access mode:

		if( acmod & 0400 )

			putchar( 'r' );

		else

			putchar( '-' );

		if( acmod & 0200 )

			putchar( 'w' );

		else

			putchar( '-' );

		if( acmod & 0100 )

			putchar( 'x' );

		else

			putchar( '-' );

		if( acmod & 040 )

			putchar( 'r' );

		else

			putchar( '-' );

		if( acmod & 020 )

			putchar( 'w' );

		else

			putchar( '-' );

		if( acmod & 010 )

			putchar( 'x' );

		else

			putchar( '-' );

		if( acmod & 04 )

			putchar( 'r' );

		else

			putchar( '-' );

		if( acmod & 02 )

			putchar( 'w' );

		else

			putchar( '-' );

		if( acmod & 01 )

			putchar( 'x' );

		else

			putchar( '-' );

	}

	if( flags & 0xa ){ // if -l or -s

		printf( "%10d", inode.st_size );

		putchar( '\t' );

	}

	if( flags & 0x4 ){

		switch( ftype ){

			case 0100 : printf( "\e[37m" );

			// Regular file

				    break;

			case 040  : printf( "\e[34m" );

			// Directory

				    break;

			case 0120 : printf( "\e[36m" );

			// Symbolic link

				    break;

			case 010  : printf( "\e[33m" );

			// Named pipe

				    break;

			case 060  : printf( "\e[32m" );

			// Block special file

				    break;

			case 016  : printf( "\e[35m" );

			// Character special file

			            break;

			case 020  : printf( "\e[35m" );

			// Device file

				    break;

			default   : putchar( '?' );

		}

	}

	char nbuf[256];

	if( (ftype == 0120) && (flags & 0x2) ){

		char lbuf[64];

		int llen = readlink( entry->d_name, lbuf, 64 );

		// Have to get the length because the result is not null-terminated for some reason

		snprintf( nbuf, strlen( entry->d_name ) + llen + 6, "%s --> %s", entry->d_name, lbuf );

	}

	else{

		snprintf( nbuf, 256, "%s", entry->d_name );

	}

	printf( "%-28s", nbuf );

	if( flags & 0x4 ){

	// Prints escape sequences in less if I don't do this

		printf( "\e[0m" );

	}

}


Edited by DarkLordofthePenguins, 18 September 2011 - 05:51 PM.

Programming is a journey, not a destination.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users