2023-10-20 19:24:35 +00:00
# include <pwd.h>
# include <grp.h>
2023-10-19 21:19:46 +00:00
# include <time.h>
2023-10-03 20:09:17 +00:00
# include <stdio.h>
# include <errno.h>
2023-10-30 15:45:24 +00:00
# include <stdlib.h>
2023-10-03 20:09:17 +00:00
# include <string.h>
2023-10-20 13:59:07 +00:00
# include <stdint.h>
2023-10-20 14:32:50 +00:00
# include <unistd.h>
2023-10-03 20:09:17 +00:00
# include <dirent.h>
2023-11-08 16:47:09 +00:00
# include <sys/stat.h>
2023-10-03 20:09:17 +00:00
# include <sys/types.h>
2023-11-09 12:09:13 +00:00
# include <sys/ioctl.h>
2023-10-31 09:53:32 +00:00
# include "make_path.h"
# include "get_stat.h"
2023-11-28 19:38:37 +00:00
# include "config.h"
2023-12-05 16:39:49 +00:00
# include "human.h"
2023-10-20 19:24:35 +00:00
2023-11-29 16:52:21 +00:00
unsigned int O_flag ;
2023-10-19 21:19:46 +00:00
unsigned int a_flag ;
unsigned int l_flag ;
2023-11-09 12:09:13 +00:00
unsigned int F_flag ;
2023-11-28 18:43:15 +00:00
unsigned int c_flag ;
2023-11-28 20:54:25 +00:00
unsigned int R_flag ;
2023-11-29 16:52:21 +00:00
unsigned int d_flag ;
unsigned int L_flag ;
2023-12-05 16:39:49 +00:00
unsigned int h_flag ;
2023-11-08 08:05:04 +00:00
unsigned int p_flag ;
2023-10-19 21:19:46 +00:00
2023-11-08 16:47:09 +00:00
struct d_node {
2023-11-14 11:35:25 +00:00
/* basename */
2023-11-08 16:47:09 +00:00
char * name ;
2023-11-10 10:10:25 +00:00
/* For free */
char * full_name ;
2023-11-08 16:47:09 +00:00
struct d_node * next ;
struct stat stats ;
} ;
2023-11-01 12:33:16 +00:00
2023-11-09 12:09:13 +00:00
/* Work with dir */
2023-11-29 17:25:24 +00:00
struct d_node * stat_file ( char * filename , int lfile ) {
/* lfile its flag. 1 if passed file from list_one() */
2023-11-08 16:47:09 +00:00
struct d_node * file = malloc ( sizeof ( struct d_node ) ) ;
if ( file = = NULL )
return NULL ;
2023-11-01 12:33:16 +00:00
2023-11-29 17:25:24 +00:00
if ( mu_get_stats ( " ls " , ! L_flag , filename , & file - > stats ) ) {
2023-11-29 16:52:21 +00:00
free ( file ) ;
2023-11-08 16:47:09 +00:00
return NULL ;
2023-11-29 16:52:21 +00:00
}
2023-11-01 12:33:16 +00:00
2023-11-10 10:10:25 +00:00
file - > full_name = filename ;
2023-11-29 16:52:21 +00:00
file - > name = strrchr ( filename , ' / ' ) ;
2023-11-29 17:25:24 +00:00
if ( file - > name = = NULL | | lfile )
2023-11-29 16:52:21 +00:00
file - > name = filename ;
else
file - > name + + ;
2023-11-08 16:47:09 +00:00
return file ;
2023-10-19 21:19:46 +00:00
}
2023-10-03 20:09:17 +00:00
2023-11-08 16:47:09 +00:00
struct d_node * * list ( const char * path , size_t * nfiles ) {
2023-10-30 15:45:24 +00:00
DIR * dp = opendir ( path ) ;
if ( dp = = NULL ) {
2023-10-20 14:32:50 +00:00
fprintf ( stderr , " ls: %s: %s \n " , path , strerror ( errno ) ) ;
2023-11-08 16:47:09 +00:00
return NULL ;
2023-10-20 14:32:50 +00:00
}
2023-11-08 16:47:09 +00:00
struct d_node * * dir , * cur , * dr = NULL ;
size_t files = 0 ;
2023-10-19 21:19:46 +00:00
struct dirent * ep ;
2023-10-03 20:09:17 +00:00
while ( ( ep = readdir ( dp ) ) ! = NULL ) {
2023-10-19 21:19:46 +00:00
if ( ep - > d_name [ 0 ] = = ' . ' & & ! a_flag )
2023-10-03 20:09:17 +00:00
continue ;
2023-10-31 09:53:32 +00:00
char * full_path = mu_make_path ( " ls " , path , ep - > d_name ) ;
2023-10-30 15:45:24 +00:00
if ( full_path = = NULL )
2023-11-08 16:47:09 +00:00
continue ;
2023-10-19 21:19:46 +00:00
2023-11-29 17:25:24 +00:00
cur = stat_file ( full_path , 0 ) ;
2023-11-29 16:52:21 +00:00
if ( cur = = NULL ) {
free ( full_path ) ;
2023-11-08 16:47:09 +00:00
continue ;
2023-11-29 16:52:21 +00:00
}
2023-10-19 21:19:46 +00:00
2023-11-08 16:47:09 +00:00
cur - > next = dr ;
dr = cur ;
files + + ;
}
2023-11-10 10:10:25 +00:00
closedir ( dp ) ;
2023-11-08 16:47:09 +00:00
if ( dr = = NULL )
return NULL ;
* nfiles = files ;
dir = malloc ( ( files + 1 ) * sizeof ( struct d_node * ) ) ;
if ( dir = = NULL ) {
fprintf ( stderr , " ls: malloc failed \n " ) ;
exit ( 1 ) ;
}
2023-11-29 19:52:35 +00:00
for ( size_t i = 0 ; ; i + + ) {
dir [ i ] = dr ;
dr = dr - > next ;
if ( dr = = NULL )
break ;
2023-10-03 20:09:17 +00:00
}
2023-11-08 16:47:09 +00:00
return dir ;
2023-10-03 20:09:17 +00:00
}
2023-11-29 17:25:24 +00:00
struct d_node * * list_one ( const char * path ) {
2023-11-29 16:52:21 +00:00
struct d_node * * dir = malloc ( sizeof ( struct d_node * ) ) ;
2023-12-05 16:50:24 +00:00
if ( dir = = NULL ) {
fprintf ( stderr , " ls: malloc failed \n " ) ;
exit ( 1 ) ;
}
2023-11-29 16:52:21 +00:00
char * new_path = strdup ( path ) ;
2023-11-29 17:25:24 +00:00
if ( new_path = = NULL ) {
free ( dir ) ;
return NULL ;
}
2023-11-29 16:52:21 +00:00
2023-11-29 17:25:24 +00:00
dir [ 0 ] = stat_file ( new_path , 1 ) ;
2023-11-29 16:52:21 +00:00
if ( dir [ 0 ] = = NULL ) {
free ( dir ) ;
return NULL ;
}
return dir ;
}
2023-11-08 16:47:09 +00:00
void dfree ( struct d_node * * dir ) {
struct d_node * cur = dir [ 0 ] , * next ;
while ( cur ! = NULL ) {
next = cur - > next ;
2023-11-10 10:10:25 +00:00
free ( cur - > full_name ) ;
2023-11-08 16:47:09 +00:00
free ( cur ) ;
cur = next ;
}
2023-10-03 20:09:17 +00:00
2023-11-08 16:47:09 +00:00
free ( dir ) ;
}
2023-10-03 20:09:17 +00:00
2023-11-09 12:09:13 +00:00
/* Print */
2023-11-21 19:18:42 +00:00
int print ( const struct d_node * node ) {
2023-11-28 18:43:15 +00:00
/* F_flag and c_flag Make output look pretty */
2023-11-21 19:18:42 +00:00
char suf = ' ' ;
2023-11-29 06:07:21 +00:00
char ind = ' - ' ;
2023-11-28 18:43:15 +00:00
char * color = " " ;
if ( S_ISDIR ( node - > stats . st_mode ) ) {
2023-11-30 07:32:18 +00:00
if ( node - > name [ strlen ( node - > name ) - 1 ] ! = ' / ' )
suf = ' / ' ;
2023-11-29 06:07:21 +00:00
ind = ' d ' ;
2023-11-28 19:38:37 +00:00
color = LS_DIR_COLOR ;
2023-11-28 18:43:15 +00:00
}
else if ( S_ISLNK ( node - > stats . st_mode ) ) {
2023-11-29 06:07:21 +00:00
suf = ' @ ' ;
ind = ' l ' ;
2023-11-28 19:38:37 +00:00
color = LS_LINK_COLOR ;
2023-11-28 18:43:15 +00:00
}
2023-11-29 06:07:21 +00:00
else if ( S_ISSOCK ( node - > stats . st_mode ) ) {
suf = ' = ' ;
ind = ' s ' ;
color = LS_SOCK_COLOR ;
}
2023-11-28 18:43:15 +00:00
2023-11-29 06:07:21 +00:00
else if ( S_ISFIFO ( node - > stats . st_mode ) ) {
suf = ' | ' ;
ind = ' p ' ;
color = LS_FIFO_COLOR ;
}
else if ( ( node - > stats . st_mode & S_IXUSR ) | | ( node - > stats . st_mode & S_IXGRP ) | | ( node - > stats . st_mode & S_IXOTH ) ) {
suf = ' * ' ;
2023-11-28 19:38:37 +00:00
color = LS_EXE_COLOR ;
2023-11-09 12:09:13 +00:00
}
2023-11-28 18:43:15 +00:00
/* Output */
2023-11-29 16:52:21 +00:00
if ( c_flag & & p_flag )
2023-11-28 18:43:15 +00:00
printf ( " %s " , color ) ;
int ret = 0 ;
2023-11-12 08:31:14 +00:00
if ( ! l_flag )
2023-11-29 06:07:21 +00:00
ret = printf ( " %s%c " , node - > name , ( F_flag ) ? suf : 0 ) ;
2023-11-10 10:10:25 +00:00
if ( l_flag ) {
2023-11-29 06:07:21 +00:00
putchar ( ind ) ;
printf ( " %c%c%c " , ( node - > stats . st_mode & S_IRUSR ) ? ' r ' : ' - ' , ( node - > stats . st_mode & S_IWUSR ) ? ' w ' : ' - ' , ( node - > stats . st_mode & S_IXUSR ) ? ' x ' : ' - ' ) ;
printf ( " %c%c%c " , ( node - > stats . st_mode & S_IRGRP ) ? ' r ' : ' - ' , ( node - > stats . st_mode & S_IWOTH ) ? ' w ' : ' - ' , ( node - > stats . st_mode & S_IXGRP ) ? ' x ' : ' - ' ) ;
printf ( " %c%c%c " , ( node - > stats . st_mode & S_IROTH ) ? ' r ' : ' - ' , ( node - > stats . st_mode & S_IWOTH ) ? ' w ' : ' - ' , ( node - > stats . st_mode & S_IXOTH ) ? ' x ' : ' - ' ) ;
2023-11-10 10:10:25 +00:00
struct tm * tm = localtime ( & node - > stats . st_mtime ) ;
char date [ 14 ] ;
if ( ! strftime ( date , sizeof ( date ) , " %b %d %H:%M " , tm ) )
2023-11-21 19:18:42 +00:00
return 0 ;
2023-11-10 10:10:25 +00:00
struct passwd * pw = getpwuid ( node - > stats . st_uid ) ;
struct group * gr = getgrgid ( node - > stats . st_gid ) ;
2023-12-05 16:39:49 +00:00
char * gr_name = ( gr ! = 0 ) ? gr - > gr_name : " nobody " ;
char * pw_name = ( pw ! = 0 ) ? pw - > pw_name : " nobody " ;
if ( h_flag )
ret = printf ( " %s %s %6s %s %s%c " , pw_name , gr_name , mu_humansize ( node - > stats . st_size ) , date , node - > name , ( F_flag ) ? suf : 0 ) ;
else
ret = printf ( " %s %s %10jd %s %s%c " , pw_name , gr_name , ( uintmax_t ) node - > stats . st_size , date , node - > name , ( F_flag ) ? suf : 0 ) ;
2023-11-10 10:10:25 +00:00
}
2023-11-21 19:18:42 +00:00
2023-11-29 16:52:21 +00:00
if ( c_flag & & p_flag )
2023-11-28 18:43:15 +00:00
printf ( " \033 [0m " ) ;
return ret ;
2023-11-09 12:09:13 +00:00
}
2023-11-21 19:18:42 +00:00
void col_print ( struct d_node * * node , size_t files , struct winsize w ) {
/* Get max len */
size_t maxlen = 0 ;
for ( size_t i = 0 ; i < files ; i + + )
if ( strlen ( node [ i ] - > name ) > maxlen )
2023-11-22 10:58:43 +00:00
maxlen = strlen ( node [ i ] - > name ) ;
2023-11-21 19:18:42 +00:00
2023-11-21 19:33:58 +00:00
/* Calc */
2023-11-30 07:32:18 +00:00
maxlen + = 3 ;
2023-11-21 19:18:42 +00:00
size_t ncols = w . ws_col / maxlen ;
size_t nrows = files ;
2023-11-21 20:18:32 +00:00
if ( ncols > 1 ) {
2023-11-21 19:18:42 +00:00
nrows = files / ncols ;
2023-11-21 20:18:32 +00:00
if ( nrows * ncols < files )
nrows + + ;
}
else
ncols = 1 ;
2023-11-21 19:18:42 +00:00
int col = 0 ;
int nexttab = 0 ;
/* Mc print */
2023-11-21 20:18:32 +00:00
for ( size_t i = 0 ; i < nrows ; i + + ) {
2023-11-21 19:18:42 +00:00
for ( size_t j = 0 ; j < ncols ; j + + ) {
2023-11-21 22:34:37 +00:00
if ( i * ncols + j < files ) {
if ( col > 0 ) {
nexttab - = col ;
2023-11-22 12:02:09 +00:00
col + = nexttab ;
2023-11-21 22:34:37 +00:00
for ( int k = 0 ; k < nexttab ; k + + )
putchar ( ' ' ) ;
}
2023-11-21 20:18:32 +00:00
2023-11-21 22:34:37 +00:00
nexttab = col + ( int ) maxlen ;
col + = print ( node [ i * ncols + j ] ) ;
2023-11-21 19:18:42 +00:00
}
}
putchar ( ' \n ' ) ;
col = 0 ;
}
}
2023-11-09 12:09:13 +00:00
2023-11-21 19:18:42 +00:00
int ls ( const char * dir_name , int label , struct winsize w ) {
2023-11-09 12:09:13 +00:00
size_t files = 0 ;
2023-11-29 16:52:21 +00:00
struct stat sb ;
if ( mu_get_stat ( " ls " , dir_name , & sb ) )
return 1 ;
struct d_node * * dir = NULL ;
2023-11-29 17:25:24 +00:00
if ( S_ISDIR ( sb . st_mode ) & & ! d_flag )
2023-11-29 16:52:21 +00:00
dir = list ( dir_name , & files ) ;
else {
2023-11-29 17:25:24 +00:00
dir = list_one ( dir_name ) ;
2023-11-29 16:52:21 +00:00
files + + ;
}
2023-11-09 12:09:13 +00:00
if ( dir = = NULL )
return 1 ;
2023-11-29 17:25:24 +00:00
if ( ( label | | R_flag ) & & ! d_flag )
2023-11-09 12:09:13 +00:00
printf ( " \n %s: \n " , dir_name ) ;
2023-11-21 19:18:42 +00:00
/* pipe print */
2023-11-29 16:52:21 +00:00
if ( ! p_flag | | l_flag | | O_flag ) {
2023-11-09 12:09:13 +00:00
for ( size_t i = 0 ; i < files ; i + + ) {
print ( dir [ i ] ) ;
putchar ( ' \n ' ) ;
}
2023-11-12 08:31:14 +00:00
}
2023-11-09 12:09:13 +00:00
2023-11-21 19:18:42 +00:00
/* mc print */
else
col_print ( dir , files , w ) ;
2023-11-09 12:09:13 +00:00
2023-11-28 20:54:25 +00:00
if ( R_flag )
for ( size_t i = 0 ; i < files ; i + + )
2023-11-29 16:52:21 +00:00
if ( S_ISDIR ( dir [ i ] - > stats . st_mode ) & & strcmp ( dir [ i ] - > name , " .. " ) & & strcmp ( dir [ i ] - > name , " . " ) )
ls ( dir [ i ] - > full_name , 1 , w ) ;
2023-11-28 20:54:25 +00:00
2023-11-09 12:09:13 +00:00
dfree ( dir ) ;
return 0 ;
}
2023-11-08 08:05:04 +00:00
int main ( int argc , char * * argv ) {
int opt ;
2023-12-05 16:39:49 +00:00
while ( ( opt = getopt ( argc , argv , " 1alFcRdLh " ) ) ! = - 1 ) {
2023-11-08 08:05:04 +00:00
switch ( opt ) {
2023-11-29 16:52:21 +00:00
case ' 1 ' :
O_flag = 1 ;
break ;
2023-11-08 08:05:04 +00:00
case ' a ' :
a_flag = 1 ;
break ;
2023-10-03 20:09:17 +00:00
2023-11-08 08:05:04 +00:00
case ' l ' :
l_flag = 1 ;
break ;
2023-10-19 21:19:46 +00:00
2023-11-09 12:09:13 +00:00
case ' F ' :
F_flag = 1 ;
break ;
2023-11-28 18:43:15 +00:00
case ' c ' :
c_flag = 1 ;
break ;
2023-11-28 20:54:25 +00:00
case ' R ' :
2023-11-29 17:25:24 +00:00
d_flag = 0 ;
2023-11-28 20:54:25 +00:00
R_flag = 1 ;
break ;
2023-11-29 16:52:21 +00:00
case ' d ' :
2023-11-29 17:25:24 +00:00
R_flag = 0 ;
2023-11-29 16:52:21 +00:00
d_flag = 1 ;
break ;
case ' L ' :
L_flag = 1 ;
break ;
2023-12-05 16:39:49 +00:00
case ' h ' :
h_flag = 1 ;
break ;
2023-11-08 08:05:04 +00:00
default :
2023-12-05 16:39:49 +00:00
printf ( " ls [dir1 dir2...] \n \t [-a Show hidden files] \n \t [-l Use a long listing format] \n \t [-F Append indicator to names] \n \t [-c Color mode] [-R Recursive] \n \t [-1 One column] [-d Print only dir names] \n \t [-L Follow symlinks] \n \t [-h Sizes in human readable format] \n " ) ;
2023-11-08 08:05:04 +00:00
return 0 ;
2023-10-03 20:09:17 +00:00
}
}
2023-11-08 08:05:04 +00:00
argv + = optind ;
argc - = optind ;
2023-10-03 20:09:17 +00:00
2023-11-09 12:09:13 +00:00
struct winsize w ;
ioctl ( STDOUT_FILENO , TIOCGWINSZ , & w ) ;
2023-11-29 16:52:21 +00:00
/* Check if programm piped, 1 - false, 0 - true */
2023-11-09 12:09:13 +00:00
p_flag = isatty ( STDOUT_FILENO ) ;
2023-11-08 16:47:09 +00:00
if ( argc < 1 )
2023-11-09 12:09:13 +00:00
ls ( " . " , 0 , w ) ;
2023-11-08 16:47:09 +00:00
if ( argc = = 1 )
2023-11-09 12:09:13 +00:00
ls ( argv [ 0 ] , 0 , w ) ;
2023-11-08 16:47:09 +00:00
2023-11-09 12:09:13 +00:00
else
for ( int i = 0 ; i < argc ; i + + )
ls ( argv [ i ] , 1 , w ) ;
2023-10-19 21:19:46 +00:00
2023-10-03 20:09:17 +00:00
return 0 ;
}