Changeset ba63912 in mainline


Ignore:
Timestamp:
2011-04-01T13:44:30Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
2859445
Parents:
a30e435
Message:

Polish the 'ls' command a little bit.

  • Cstyle fixes.
  • Avoid some code duplication.
  • Call stat() only once per each printed file.
  • Print directories first, files second.
Location:
uspace/app/bdsh/cmds/modules/ls
Files:
2 edited

Legend:

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

    ra30e435 rba63912  
    4848#include "util.h"
    4949#include "entry.h"
    50 #include "ls.h"
    5150#include "cmds.h"
     51
     52/* Various values that can be returned by ls_scope() */
     53#define LS_BOGUS 0
     54#define LS_FILE  1
     55#define LS_DIR   2
     56
     57/** Structure to represent a directory entry.
     58 *
     59 * Useful to keep together important informations
     60 * for sorting directory entries.
     61 */
     62struct dir_elem_t {
     63        char *name;
     64        struct stat s;
     65};
    5266
    5367static const char *cmdname = "ls";
     
    5973};
    6074
     75/** Print an entry.
     76 *
     77 * ls_print currently does nothing more than print the entry.
     78 * In the future, we will likely pass the absolute path, and
     79 * some sort of ls_options structure that controls how each
     80 * entry is printed and what is printed about it.
     81 *
     82 * Now we just print basic DOS style lists.
     83 *
     84 * @param de            Directory element.
     85 */
     86static void ls_print(struct dir_elem_t *de)
     87{
     88        if (de->s.is_file)
     89                printf("%-40s\t%llu\n", de->name, (long long) de->s.size);
     90        else if (de->s.is_directory)
     91                printf("%-40s\t<dir>\n", de->name);
     92        else
     93                printf("%-40s\n", de->name);
     94}
     95
     96
    6197/** Compare 2 directory elements.
    6298 *
    6399 * It compares 2 elements of a directory : a file is considered
    64  * as lower than a directory, and if they have the same type,
     100 * as bigger than a directory, and if they have the same type,
    65101 * they are compared alphabetically.
    66102 *
    67103 * @param a             Pointer to the structure of the first element.
    68104 * @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.
     105 * @param arg           Pointer for an other and optionnal argument.
     106 *
     107 * @return              -1 if a < b, 1 otherwise.
    73108 */
    74109static int ls_cmp(void *a, void *b, void *arg)
    75110{
    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))
     111        struct dir_elem_t *da = a;
     112        struct dir_elem_t *db = b;
     113       
     114        if ((da->s.is_directory && db->s.is_file) ||
     115            ((da->s.is_directory == db->s.is_directory) &&
     116            str_cmp(da->name, db->name) < 0))
    85117                return -1;
    86118        else
     
    100132{
    101133        int alloc_blocks = 20;
    102         int i = 0;
     134        int i;
    103135        int nbdirs = 0;
    104         int rc = 0;
    105         char * buff = NULL;
    106         struct dir_elem_t * tmp = NULL;
    107         struct dir_elem_t * tosort = NULL;
    108         struct dirent * dp = NULL;
    109         struct stat s;
    110        
    111         if (! dirp)
     136        int rc;
     137        int len;
     138        char *buff;
     139        struct dir_elem_t *tmp;
     140        struct dir_elem_t *tosort;
     141        struct dirent *dp;
     142       
     143        if (!dirp)
    112144                return;
    113145
    114         buff = (char *)malloc(PATH_MAX);
    115         if (NULL == buff) {
     146        buff = (char *) malloc(PATH_MAX);
     147        if (!buff) {
    116148                cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    117149                return;
    118150        }
    119         memset(buff, 0, sizeof(buff));
    120        
    121         if (!sort) {
    122                 while ((dp = readdir(dirp))) {
    123                         memset(buff, 0, sizeof(buff));
    124                         /* Don't worry if inserting a double slash, this will be fixed by
    125                          * absolutize() later with subsequent calls to open() or readdir() */
    126                         snprintf(buff, PATH_MAX - 1, "%s/%s", d, dp->d_name);
    127                         ls_print(dp->d_name, buff);
    128                 }
    129 
    130                 free(buff);
    131 
    132                 return;
    133         }
    134        
    135         tosort = (struct dir_elem_t *)malloc(alloc_blocks*sizeof(struct dir_elem_t));
    136         if (NULL == tosort) {
     151       
     152        tosort = (struct dir_elem_t *) malloc(alloc_blocks * sizeof(*tosort));
     153        if (!tosort) {
    137154                cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    138155                free(buff);
    139156                return;
    140157        }
    141         memset(tosort, 0, sizeof(tosort));
    142158       
    143159        while ((dp = readdir(dirp))) {
    144                 nbdirs++;
    145                
    146                 if (nbdirs > alloc_blocks) {
     160                if (nbdirs + 1 > alloc_blocks) {
    147161                        alloc_blocks += alloc_blocks;
    148162                       
    149                         tmp = (struct dir_elem_t *)realloc(tosort,
    150                                         alloc_blocks*sizeof(struct dir_elem_t));
    151                         if (NULL == tmp) {
     163                        tmp = (struct dir_elem_t *) realloc(tosort,
     164                            alloc_blocks * sizeof(struct dir_elem_t));
     165                        if (!tmp) {
    152166                                cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    153                                 for(i=0;i<(nbdirs-1);i++) {
    154                                         free(tosort[i].name);
    155                                 }
    156                                 free(tosort);
    157                                 free(buff);
    158                                 return;
     167                                goto out;
    159168                        }
    160                        
    161169                        tosort = tmp;
    162170                }
    163171               
    164                 // fill the name field
    165                 tosort[nbdirs-1].name = (char *)malloc(str_length(dp->d_name)+1);
    166                 if (NULL == tosort[nbdirs-1].name) {
     172                /* fill the name field */
     173                tosort[nbdirs].name = (char *) malloc(str_length(dp->d_name) + 1);
     174                if (!tosort[nbdirs].name) {
    167175                        cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    168                         for(i=0;i<(nbdirs-1);i++) {
    169                                 free(tosort[i].name);
    170                         }
    171                         free(tosort);
    172                         free(buff);
    173                         return;
     176                        goto out;
    174177                }
    175178               
    176                 memset(tosort[nbdirs-1].name, 0, str_length(dp->d_name)+1);
    177                 str_cpy(tosort[nbdirs-1].name, str_length(dp->d_name)+1, dp->d_name);
    178                
    179                 // fill the isdir field
    180                 memset(buff, 0, sizeof(buff));
    181                 snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[nbdirs-1].name);
    182                
    183                 rc = stat(buff, &s);
     179                str_cpy(tosort[nbdirs].name, str_length(dp->d_name) + 1, dp->d_name);
     180                len = snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[nbdirs].name);
     181                buff[len] = '\0';
     182
     183                rc = stat(buff, &tosort[nbdirs++].s);
    184184                if (rc != 0) {
    185185                        printf("ls: skipping bogus node %s\n", buff);
    186186                        printf("rc=%d\n", rc);
    187                         for(i=0;i<nbdirs;i++) {
    188                                 free(tosort[i].name);
    189                         }
    190                         free(tosort);
    191                         free(buff);
    192                         return;
    193                 }
    194                
    195                 tosort[nbdirs-1].isdir = s.is_directory ? 1 : 0;
    196         }
    197        
    198         if (!qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t), ls_cmp, NULL)) {
    199                 printf("Sorting error.\n");
    200         }
    201        
    202         for(i=0;i<nbdirs;i++) {
    203                 memset(buff, 0, sizeof(buff));
    204                 /* Don't worry if inserting a double slash, this will be fixed by
    205                  * absolutize() later with subsequent calls to open() or readdir() */
    206                 snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[i].name);
    207                 ls_print(tosort[i].name, buff);
     187                        goto out;
     188                }
     189        }
     190       
     191        if (sort) {
     192                if (!qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t),
     193                    ls_cmp, NULL)) {
     194                        printf("Sorting error.\n");
     195                }
     196        }
     197       
     198        for (i = 0; i < nbdirs; i++)
     199                ls_print(&tosort[i]);
     200       
     201out:
     202        for(i = 0; i < nbdirs; i++)
    208203                free(tosort[i].name);
    209         }
    210        
    211204        free(tosort);
    212205        free(buff);
    213 
    214         return;
    215 }
    216 
    217 /** Print an entry.
    218  *
    219  * ls_print currently does nothing more than print the entry.
    220  * In the future, we will likely pass the absolute path, and
    221  * some sort of ls_options structure that controls how each
    222  * entry is printed and what is printed about it.
    223  *
    224  * Now we just print basic DOS style lists.
    225  *
    226  * @param name          Name of the entry.
    227  * @param pathname      Path of the entry.
    228  */
    229 static void ls_print(const char *name, const char *pathname)
    230 {
    231         struct stat s;
    232         int rc;
    233 
    234         rc = stat(pathname, &s);
    235         if (rc != 0) {
    236                 /* Odd chance it was deleted from the time readdir() found it */
    237                 printf("ls: skipping bogus node %s\n", pathname);
    238                 printf("rc=%d\n", rc);
    239                 return;
    240         }
    241        
    242         if (s.is_file)
    243                 printf("%-40s\t%llu\n", name, (long long) s.size);
    244         else if (s.is_directory)
    245                 printf("%-40s\t<dir>\n", name);
    246         else
    247                 printf("%-40s\n", name);
    248 
    249         return;
    250206}
    251207
     
    271227{
    272228        unsigned int argc;
    273         struct stat s;
    274         char *buff;
     229        struct dir_elem_t de;
    275230        DIR *dirp;
    276231        int c, opt_ind;
     
    291246        }
    292247       
    293         int dir = (int)argc > optind ? (int)argc-1 : optind-1;
    294         argc -= (optind-1);
    295        
    296         buff = (char *) malloc(PATH_MAX);
    297         if (NULL == buff) {
     248        int dir = (int) argc > optind ? (int) argc - 1 : optind - 1;
     249        argc -= (optind - 1);
     250       
     251        de.name = (char *) malloc(PATH_MAX);
     252        if (!de.name) {
    298253                cli_error(CL_ENOMEM, "%s: ", cmdname);
    299254                return CMD_FAILURE;
    300255        }
    301         memset(buff, 0, sizeof(buff));
     256        memset(de.name, 0, sizeof(PATH_MAX));
    302257       
    303258        if (argc == 1)
    304                 getcwd(buff, PATH_MAX);
     259                getcwd(de.name, PATH_MAX);
    305260        else
    306                 str_cpy(buff, PATH_MAX, argv[dir]);
    307        
    308         if (stat(buff, &s)) {
    309                 cli_error(CL_ENOENT, buff);
    310                 free(buff);
     261                str_cpy(de.name, PATH_MAX, argv[dir]);
     262       
     263        if (stat(de.name, &de.s)) {
     264                cli_error(CL_ENOENT, de.name);
     265                free(de.name);
    311266                return CMD_FAILURE;
    312267        }
    313268
    314         if (s.is_file) {
    315                 ls_print(buff, buff);
     269        if (de.s.is_file) {
     270                ls_print(&de);
    316271        } else {
    317                 dirp = opendir(buff);
     272                dirp = opendir(de.name);
    318273                if (!dirp) {
    319274                        /* May have been deleted between scoping it and opening it */
    320                         cli_error(CL_EFAIL, "Could not stat %s", buff);
    321                         free(buff);
     275                        cli_error(CL_EFAIL, "Could not stat %s", de.name);
     276                        free(de.name);
    322277                        return CMD_FAILURE;
    323278                }
    324                 ls_scan_dir(buff, dirp, sort);
     279                ls_scan_dir(de.name, dirp, sort);
    325280                closedir(dirp);
    326281        }
    327282
    328         free(buff);
     283        free(de.name);
    329284
    330285        return CMD_SUCCESS;
  • uspace/app/bdsh/cmds/modules/ls/ls.h

    ra30e435 rba63912  
    22#define LS_H
    33
    4 /* Various values that can be returned by ls_scope() */
    5 #define LS_BOGUS 0
    6 #define LS_FILE  1
    7 #define LS_DIR   2
    8 
    9 static void ls_scan_dir(const char *, DIR *, int);
    10 static 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  */
    17 struct dir_elem_t {
    18         char * name;
    19         int isdir;
    20 };
    214
    225#endif /* LS_H */
Note: See TracChangeset for help on using the changeset viewer.