Changeset e3a3e3ad in mainline


Ignore:
Timestamp:
2011-03-30T17:24:01Z (14 years ago)
Author:
Jerome Portal <jeromeportal1@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
beb6b3d
Parents:
99b65d2
Message:

improve ls sorting, and add -h and -u options

Location:
uspace/app/bdsh/cmds/modules/ls
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/bdsh/cmds/modules/ls/ls.c

    r99b65d2 re3a3e3ad  
    3838#include <dirent.h>
    3939#include <fcntl.h>
     40#include <getopt.h>
    4041#include <sys/types.h>
    4142#include <sys/stat.h>
    4243#include <str.h>
     44#include <sort.h>
    4345
    4446#include "errors.h"
     
    5153static const char *cmdname = "ls";
    5254
    53 /** Sort array of files/directories
    54  *
    55  * Sort an array containing files and directories,
    56  * in alphabetical order, with files first.
    57  *
    58  * @param d                     Current directory.
    59  * @param tab           Array of file/directories to sort.
    60  * @param nbdirs        Number of elements.
    61  *
     55static struct option const long_options[] = {
     56        { "help", no_argument, 0, 'h' },
     57        { "unsort", no_argument, 0, 'u' },     
     58        { 0, 0, 0, 0 }
     59};
     60
     61/** Compare 2 directory elements.
     62 *
     63 * It compares 2 elements of a directory : a file is considered
     64 * as lower than a directory, and if they have the same type,
     65 * they are compared alphabetically.
     66 *
     67 * @param a             Pointer to the structure of the first element.
     68 * @param b             Pointer to the structure of the second element.
     69 * @param arg   Pointer for an other and optionnal argument.
     70 *
     71 * @return              -1 if a < b,
     72 *                              1 otherwise.
    6273 */
    63 static void ls_sort_dir(const char *d, char ** tab, int nbdirs)
    64 {
    65         int i = 0;
    66         int j = 0;
    67         int min = 0;
    68         int rc;
    69         char * buff1 = NULL;
    70         char * buff2 = NULL;
    71         char * tmp = NULL;
    72         struct stat s1;
    73         struct stat s2;
    74        
    75         buff1 = (char *)malloc(PATH_MAX);
    76         if (NULL == buff1) {
    77                 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    78                 return;
    79         }
    80        
    81         buff2 = (char *)malloc(PATH_MAX);
    82         if (NULL == buff2) {
    83                 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    84                 return;
    85         }
    86        
    87         for(i=0;i<nbdirs;i++) {
    88                 min = i;
    89                
    90                 for(j=i;j<nbdirs;j++) {
    91                         memset(buff1, 0, sizeof(buff1));
    92                         memset(buff2, 0, sizeof(buff2));
    93                         snprintf(buff1, PATH_MAX - 1, "%s/%s", d, tab[min]);
    94                         snprintf(buff2, PATH_MAX - 1, "%s/%s", d, tab[j]);
    95                        
    96                         rc = stat(buff1, &s1);
    97                         if (rc != 0) {
    98                                 printf("ls: skipping bogus node %s\n", buff1);
    99                                 printf("rc=%d\n", rc);
    100                                 return;
    101                         }
    102                        
    103                         rc = stat(buff2, &s2);
    104                         if (rc != 0) {
    105                                 printf("ls: skipping bogus node %s\n", buff2);
    106                                 printf("rc=%d\n", rc);
    107                                 return;
    108                         }
    109                        
    110                         if ((s2.is_file && s1.is_directory)
    111                                 || (((s2.is_file && s1.is_file)
    112                                 || (s2.is_directory && s1.is_directory))
    113                                 && str_cmp(tab[min], tab[j]) > 0))
    114                             min = j;
    115                 }
    116                
    117                 tmp = tab[i];
    118                 tab[i] = tab[min];
    119                 tab[min] = tmp;
    120         }
    121        
    122         free(buff1);
    123         free(buff2);
    124        
    125         return;
     74static int ls_cmp(void *a, void *b, void *arg)
     75{
     76        int a_isdir = (*((struct dir_elem_t *)a)).isdir;
     77        char * a_name = (*((struct dir_elem_t *)a)).name;
     78       
     79        int b_isdir = (*((struct dir_elem_t *)b)).isdir;
     80        char * b_name = (*((struct dir_elem_t *)b)).name;
     81       
     82        if ((!a_isdir && b_isdir)
     83                || (((!b_isdir && !a_isdir) || (b_isdir && a_isdir))
     84                && str_cmp(a_name, b_name) < 0))
     85                return -1;
     86        else
     87                return 1;
    12688}
    12789
     
    13294 * @param d             Name of the directory.
    13395 * @param dirp  Directory stream.
    134  *
    13596 */
    136 static void ls_scan_dir(const char *d, DIR *dirp)
     97static void ls_scan_dir(const char *d, DIR *dirp, int sort)
    13798{
    13899        int alloc_blocks = 20;
    139100        int i = 0;
    140101        int nbdirs = 0;
     102        int rc = 0;
    141103        char * buff = NULL;
    142         char ** tmp = NULL;
    143         char ** tosort = NULL;
     104        struct dir_elem_t * tmp = NULL;
     105        struct dir_elem_t * tosort = NULL;
    144106        struct dirent * dp = NULL;
    145 
     107        struct stat s;
     108       
    146109        if (! dirp)
    147110                return;
     
    152115                return;
    153116        }
    154        
    155         tosort = (char **)malloc(alloc_blocks*sizeof(char *));
     117        memset(buff, 0, sizeof(buff));
     118       
     119        if (!sort) {
     120                while ((dp = readdir(dirp))) {
     121                        memset(buff, 0, sizeof(buff));
     122                        /* Don't worry if inserting a double slash, this will be fixed by
     123                         * absolutize() later with subsequent calls to open() or readdir() */
     124                        snprintf(buff, PATH_MAX - 1, "%s/%s", d, dp->d_name);
     125                        ls_print(dp->d_name, buff);
     126                }
     127
     128                free(buff);
     129
     130                return;
     131        }
     132       
     133        tosort = (struct dir_elem_t *)malloc(alloc_blocks*sizeof(struct dir_elem_t));
    156134        if (NULL == tosort) {
    157135                cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
     136                free(buff);
    158137                return;
    159138        }
     
    166145                        alloc_blocks += alloc_blocks;
    167146                       
    168                         tmp = (char **)realloc(tosort, (alloc_blocks)*sizeof(char *));
     147                        tmp = (struct dir_elem_t *)realloc(tosort,
     148                                        alloc_blocks*sizeof(struct dir_elem_t));
    169149                        if (NULL == tmp) {
    170150                                cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
     151                                for(i=0;i<(nbdirs-1);i++) {
     152                                        free(tosort[i].name);
     153                                }
     154                                free(tosort);
     155                                free(buff);
    171156                                return;
    172157                        }
     
    175160                }
    176161               
    177                 tosort[nbdirs-1] = (char *)malloc(str_length(dp->d_name)+1);
    178                 if (NULL == tosort[nbdirs-1]) {
    179                                 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    180                                 return;
    181                 }
    182                 memset(tosort[nbdirs-1], 0, str_length(dp->d_name)+1);
    183                
    184                 str_cpy(tosort[nbdirs-1], str_length(dp->d_name)+1, dp->d_name);
    185         }
    186        
    187         ls_sort_dir(d, tosort, nbdirs);
     162                // fill the name field
     163                tosort[nbdirs-1].name = (char *)malloc(str_length(dp->d_name)+1);
     164                if (NULL == tosort[nbdirs-1].name) {
     165                        cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
     166                        for(i=0;i<(nbdirs-1);i++) {
     167                                free(tosort[i].name);
     168                        }
     169                        free(tosort);
     170                        free(buff);
     171                        return;
     172                }
     173               
     174                memset(tosort[nbdirs-1].name, 0, str_length(dp->d_name)+1);
     175                str_cpy(tosort[nbdirs-1].name, str_length(dp->d_name)+1, dp->d_name);
     176               
     177                // fill the isdir field
     178                memset(buff, 0, sizeof(buff));
     179                snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[nbdirs-1].name);
     180               
     181                rc = stat(buff, &s);
     182                if (rc != 0) {
     183                        printf("ls: skipping bogus node %s\n", buff);
     184                        printf("rc=%d\n", rc);
     185                        for(i=0;i<nbdirs;i++) {
     186                                free(tosort[i].name);
     187                        }
     188                        free(tosort);
     189                        free(buff);
     190                        return;
     191                }
     192               
     193                tosort[nbdirs-1].isdir = s.is_directory ? 1 : 0;
     194        }
     195       
     196        if (!qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t), ls_cmp, NULL)) {
     197                printf("Sorting error.\n");
     198        }
    188199       
    189200        for(i=0;i<nbdirs;i++) {
     
    191202                /* Don't worry if inserting a double slash, this will be fixed by
    192203                 * absolutize() later with subsequent calls to open() or readdir() */
    193                 snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[i]);
    194                 ls_print(tosort[i], buff);
    195                 free(tosort[i]);
     204                snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[i].name);
     205                ls_print(tosort[i].name, buff);
     206                free(tosort[i].name);
    196207        }
    197208       
     
    202213}
    203214
    204 /* ls_print currently does nothing more than print the entry.
    205  * in the future, we will likely pass the absolute path, and
     215/** Print an entry.
     216 *
     217 * ls_print currently does nothing more than print the entry.
     218 * In the future, we will likely pass the absolute path, and
    206219 * some sort of ls_options structure that controls how each
    207220 * entry is printed and what is printed about it.
    208221 *
    209  * Now we just print basic DOS style lists */
    210 
     222 * Now we just print basic DOS style lists.
     223 *
     224 * @param name          Name of the entry.
     225 * @param pathname      Path of the entry.
     226 */
    211227static void ls_print(const char *name, const char *pathname)
    212228{
     
    238254        } else {
    239255                help_cmd_ls(HELP_SHORT);
    240                 printf("  `%s' [path], if no path is given the current "
    241                                 "working directory is used.\n", cmdname);
     256                printf(
     257                "Usage:  %s [options] [path]\n"
     258                "If not path is given, the current working directory is used.\n"
     259                "Options:\n"
     260                "  -h, --help       A short option summary\n"
     261                "  -u, --unsort     Do not sort directory entries\n",
     262                cmdname);
    242263        }
    243264
     
    251272        char *buff;
    252273        DIR *dirp;
     274        int c, opt_ind;
     275        int sort = 1;
    253276
    254277        argc = cli_count_args(argv);
    255 
     278       
     279        for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
     280                c = getopt_long(argc, argv, "hu", long_options, &opt_ind);
     281                switch (c) {
     282                case 'h':
     283                        help_cmd_ls(HELP_LONG);
     284                        return CMD_SUCCESS;
     285                case 'u':
     286                        sort = 0;
     287                        break;
     288                }
     289        }
     290       
     291        int dir = (int)argc > optind ? (int)argc-1 : optind-1;
     292        argc -= (optind-1);
     293       
    256294        buff = (char *) malloc(PATH_MAX);
    257295        if (NULL == buff) {
     
    260298        }
    261299        memset(buff, 0, sizeof(buff));
    262 
     300       
    263301        if (argc == 1)
    264302                getcwd(buff, PATH_MAX);
    265303        else
    266                 str_cpy(buff, PATH_MAX, argv[1]);
    267 
     304                str_cpy(buff, PATH_MAX, argv[dir]);
     305       
    268306        if (stat(buff, &s)) {
    269307                cli_error(CL_ENOENT, buff);
     
    282320                        return CMD_FAILURE;
    283321                }
    284                 ls_scan_dir(buff, dirp);
     322                ls_scan_dir(buff, dirp, sort);
    285323                closedir(dirp);
    286324        }
  • uspace/app/bdsh/cmds/modules/ls/ls.h

    r99b65d2 re3a3e3ad  
    77#define LS_DIR   2
    88
    9 static void ls_sort_dir(const char *, char **, int);
    10 static void ls_scan_dir(const char *, DIR *);
     9static void ls_scan_dir(const char *, DIR *, int);
    1110static void ls_print(const char *, const char *);
     11
     12/** Structure to represent a directory entry.
     13 *
     14 * Useful to keep together important informations
     15 * for sorting directory entries.
     16 */
     17struct dir_elem_t {
     18        char * name;
     19        int isdir;
     20};
    1221
    1322#endif /* LS_H */
Note: See TracChangeset for help on using the changeset viewer.