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>
2024-03-17 21:46:58 +00:00
# include "mode_to_str.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
2024-03-03 13:34:11 +00:00
char O_flag ;
char a_flag ;
char l_flag ;
char F_flag ;
char c_flag ;
char R_flag ;
char d_flag ;
char L_flag ;
char h_flag ;
char s_flag ;
char i_flag ;
char p_flag ;
2024-01-21 10:07:27 +00:00
int sortd ( const void * p1 , const void * p2 ) ;
int ( * sorter ) ( const void * p1 , const void * p2 ) = sortd ;
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-12-23 13:45:31 +00:00
struct d_node * * list ( const char * path , size_t * nfiles , int * ret ) {
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
}
2024-04-12 15:59:13 +00:00
struct d_node * dn , * cur ;
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
2024-04-12 15:59:13 +00:00
cur = stat_file ( full_path , 0 ) ;
if ( cur = = NULL ) {
2023-12-23 13:45:31 +00:00
* ret = 1 ;
2023-11-29 16:52:21 +00:00
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
2024-04-12 15:59:13 +00:00
cur - > next = dn ;
dn = cur ;
2024-03-26 05:36:15 +00:00
( * nfiles ) + + ;
2023-11-08 16:47:09 +00:00
}
2023-11-10 10:10:25 +00:00
closedir ( dp ) ;
2024-04-12 15:59:13 +00:00
if ( dn = = NULL )
return NULL ;
struct d_node * * dir = malloc ( * nfiles * sizeof ( struct d_node * ) ) ;
if ( dir = = NULL ) {
fprintf ( stderr , " ls: malloc failed \n " ) ;
return NULL ;
}
for ( int i = 0 ; i < * nfiles ; i + + ) {
dir [ i ] = dn ;
dn = dn - > next ;
}
2023-11-08 16:47:09 +00:00
return dir ;
2023-10-03 20:09:17 +00:00
}
2023-12-23 13:45:31 +00:00
struct d_node * * list_one ( const char * path , int * ret ) {
2024-01-07 10:14:47 +00:00
struct d_node * * dir = malloc ( sizeof ( struct d_node * ) * 2 ) ;
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 ) ;
2024-03-22 17:33:38 +00:00
if ( new_path = = NULL )
goto ERROR ;
2023-11-29 16:52:21 +00:00
2023-11-29 17:25:24 +00:00
dir [ 0 ] = stat_file ( new_path , 1 ) ;
2024-03-22 17:33:38 +00:00
if ( dir [ 0 ] = = NULL )
goto ERROR_PATH ;
2023-11-29 16:52:21 +00:00
2024-01-07 10:14:47 +00:00
dir [ 1 ] = NULL ;
2023-11-29 16:52:21 +00:00
return dir ;
2024-03-22 17:33:38 +00:00
ERROR_PATH :
* ret = 1 ;
free ( new_path ) ;
ERROR :
free ( dir ) ;
return NULL ;
2023-11-29 16:52:21 +00:00
}
2024-01-07 10:43:31 +00:00
void dfree ( struct d_node * * dir , size_t files ) {
for ( size_t i = 0 ; i < files ; i + + ) {
2024-01-07 10:14:47 +00:00
free ( dir [ i ] - > full_name ) ;
free ( dir [ i ] ) ;
2023-11-08 16:47:09 +00:00
}
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
2024-02-16 14:20:01 +00:00
char * get_date ( time_t mtime ) {
2024-03-27 19:04:17 +00:00
static char date [ 100 ] ;
2024-03-22 17:33:38 +00:00
2024-03-27 19:04:17 +00:00
strftime ( date , sizeof ( date ) , " %b %d %H:%M " , localtime ( & mtime ) ) ;
2024-03-22 17:33:38 +00:00
2024-03-27 19:04:17 +00:00
return date ;
2023-12-23 13:45:31 +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 ) {
char suf = ' ' ;
2023-11-28 18:43:15 +00:00
char * color = " " ;
2024-03-10 11:09:27 +00:00
2024-03-17 21:46:58 +00:00
char * mode = mu_mode_2_str ( node - > stats . st_mode ) ;
2023-11-28 18:43:15 +00:00
if ( S_ISDIR ( node - > stats . st_mode ) ) {
2023-11-30 07:32:18 +00:00
if ( node - > name [ strlen ( node - > name ) - 1 ] ! = ' / ' )
suf = ' / ' ;
2024-03-10 11:09:27 +00:00
mode [ 0 ] = ' 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 = ' @ ' ;
2024-03-10 11:09:27 +00:00
mode [ 0 ] = ' 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 = ' = ' ;
2024-03-10 11:09:27 +00:00
mode [ 0 ] = ' s ' ;
2023-11-29 06:07:21 +00:00
color = LS_SOCK_COLOR ;
}
2023-11-28 18:43:15 +00:00
2024-03-10 11:09:27 +00:00
else if ( S_ISBLK ( node - > stats . st_mode ) ) {
mode [ 0 ] = ' b ' ;
color = LS_BLOCK_COLOR ;
}
2023-11-29 06:07:21 +00:00
else if ( S_ISFIFO ( node - > stats . st_mode ) ) {
suf = ' | ' ;
2024-03-10 11:09:27 +00:00
mode [ 0 ] = ' p ' ;
2023-11-29 06:07:21 +00:00
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-12-19 20:05:42 +00:00
int ret = 0 ;
if ( i_flag )
2024-03-27 19:04:17 +00:00
ret + = printf ( " %7jd " , node - > stats . st_ino ) ;
2023-11-28 18:43:15 +00:00
2024-01-07 19:15:04 +00:00
if ( s_flag ) {
2024-03-02 11:07:19 +00:00
off_t size = 512 * node - > stats . st_blocks ;
2024-01-07 19:15:04 +00:00
if ( h_flag )
2024-02-21 09:12:37 +00:00
ret + = printf ( " %7s " , mu_humansize ( size , 1024 ) ) ;
2024-01-07 19:15:04 +00:00
else
2024-03-27 19:04:17 +00:00
ret + = printf ( " %7jd " , size / 1024 ) ;
2024-01-07 19:15:04 +00:00
}
2023-11-10 10:10:25 +00:00
if ( l_flag ) {
2024-03-10 11:09:27 +00:00
printf ( " %s " , mode ) ;
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 )
2024-03-27 19:04:17 +00:00
ret + = printf ( " %4u %4s %6s %6s %s " , node - > stats . st_nlink , pw_name , gr_name , mu_humansize ( node - > stats . st_size , 1024 ) , get_date ( node - > stats . st_mtime ) ) ;
2023-12-05 16:39:49 +00:00
else
2024-03-27 19:04:17 +00:00
ret + = printf ( " %4u %4s %6s %10ld %s " , node - > stats . st_nlink , pw_name , gr_name , node - > stats . st_size , get_date ( node - > stats . st_mtime ) ) ;
2023-11-10 10:10:25 +00:00
}
2023-11-21 19:18:42 +00:00
2024-01-07 19:22:34 +00:00
if ( c_flag & & p_flag )
printf ( " %s " , color ) ;
2024-02-16 14:20:01 +00:00
ret + = printf ( " %s " , node - > name ) ;
2023-11-29 16:52:21 +00:00
if ( c_flag & & p_flag )
2023-11-28 18:43:15 +00:00
printf ( " \033 [0m " ) ;
2024-02-16 14:20:01 +00:00
printf ( " %c " , ( F_flag ) ? suf : 0 ) ;
2023-11-28 18:43:15 +00:00
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-12-19 20:05:42 +00:00
if ( i_flag )
maxlen + = 10 ;
2024-01-07 19:15:04 +00:00
if ( s_flag )
maxlen + = 10 ;
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-12-17 08:23:09 +00:00
size_t index = j * nrows + i ;
if ( index < files ) {
2023-11-21 22:34:37 +00:00
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 ;
2023-12-17 08:23:09 +00:00
col + = print ( node [ index ] ) ;
2023-11-21 19:18:42 +00:00
}
}
putchar ( ' \n ' ) ;
col = 0 ;
}
}
2023-11-09 12:09:13 +00:00
2023-12-23 13:45:31 +00:00
/* Sort */
int sortt ( const void * p1 , const void * p2 ) {
return ( * ( struct d_node * * ) p2 ) - > stats . st_mtime - ( * ( struct d_node * * ) p1 ) - > stats . st_mtime ;
}
int sorts ( const void * p1 , const void * p2 ) {
2024-03-22 17:33:38 +00:00
return ( * ( struct d_node * * ) p2 ) - > stats . st_size - ( * ( struct d_node * * ) p1 ) - > stats . st_size < = 10 ;
2023-12-23 13:45:31 +00:00
}
2024-01-21 10:07:27 +00:00
int sortd ( const void * p1 , const void * p2 ) {
2024-03-22 17:33:38 +00:00
return strcmp ( ( * ( struct d_node * * ) p1 ) - > full_name , ( * ( struct d_node * * ) p2 ) - > full_name ) ;
2024-01-21 10:07:27 +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-12-23 13:45:31 +00:00
int ret = 0 ;
2023-11-29 16:52:21 +00:00
struct stat sb ;
if ( mu_get_stat ( " ls " , dir_name , & sb ) )
return 1 ;
2023-12-23 13:45:31 +00:00
int its_file = 0 ;
2023-11-29 16:52:21 +00:00
struct d_node * * dir = NULL ;
2023-11-29 17:25:24 +00:00
if ( S_ISDIR ( sb . st_mode ) & & ! d_flag )
2023-12-23 13:45:31 +00:00
dir = list ( dir_name , & files , & ret ) ;
2023-11-29 16:52:21 +00:00
else {
2023-12-23 13:45:31 +00:00
dir = list_one ( dir_name , & ret ) ;
its_file = 1 ;
2024-01-07 10:43:31 +00:00
files = 1 ;
2023-11-29 16:52:21 +00:00
}
2023-11-09 12:09:13 +00:00
if ( dir = = NULL )
return 1 ;
2024-03-22 17:33:38 +00:00
qsort ( dir , files , sizeof ( struct d_node * ) , sorter ) ;
2023-12-23 13:45:31 +00:00
if ( ( label | | R_flag ) & & ! d_flag & & ! its_file )
2024-03-10 11:09:27 +00:00
printf ( " %s: \n " , dir_name ) ;
2023-11-09 12:09:13 +00:00
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
2024-01-07 10:43:31 +00:00
dfree ( dir , files ) ;
2023-12-23 13:45:31 +00:00
return ret ;
2023-11-09 12:09:13 +00:00
}
2023-11-08 08:05:04 +00:00
int main ( int argc , char * * argv ) {
int opt ;
2024-01-07 19:15:04 +00:00
while ( ( opt = getopt ( argc , argv , " 1alFcRdLhistS " ) ) ! = - 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-12-19 20:05:42 +00:00
case ' i ' :
i_flag = 1 ;
break ;
2024-01-07 19:15:04 +00:00
case ' s ' :
s_flag = 1 ;
break ;
2023-12-23 13:45:31 +00:00
case ' t ' :
sorter = sortt ;
break ;
case ' S ' :
sorter = sorts ;
break ;
2023-11-08 08:05:04 +00:00
default :
2024-03-03 13:34:11 +00:00
printf ( " ls [1alFcRdLhistS] [dir1 file2...] \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 \n \t -R Recursive \n \t -1 One column \n \t -d Print only dir names \n \t -L Follow symlinks \n \t -h Sizes in human readable format \n \t -i Listen inodes \n \t -t Sort by mtime \n \t -S Sort by size \n \t -s Print file size \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-12-23 13:45:31 +00:00
return ls ( " . " , 0 , w ) ;
2023-11-08 16:47:09 +00:00
2024-01-07 10:14:47 +00:00
else if ( argc = = 1 )
2023-12-23 13:45:31 +00:00
return ls ( argv [ 0 ] , 0 , w ) ;
2023-11-08 16:47:09 +00:00
2024-01-07 10:14:47 +00:00
else {
int ret = 0 ;
2023-11-09 12:09:13 +00:00
for ( int i = 0 ; i < argc ; i + + )
2023-12-23 13:45:31 +00:00
if ( ls ( argv [ i ] , 1 , w ) )
ret = 1 ;
2023-10-19 21:19:46 +00:00
2024-01-07 10:14:47 +00:00
return ret ;
}
return 0 ;
2023-10-03 20:09:17 +00:00
}