Vladar

homebrew ls

Nov 6th, 2014
233
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.21 KB | None | 0 0
  1. /**
  2.  * \file
  3.  * \author Vladar <[email protected]>
  4.  * \version 1.1
  5.  * \brief *nix ls command implementation.
  6.  *
  7.  * \copyright \parblock
  8.  * Copyright (c) 2014 Vladar <[email protected]>
  9.  *
  10.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  11.  * of this software and associated documentation files (the "Software"), to deal
  12.  * in the Software without restriction, including without limitation the rights
  13.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14.  * copies of the Software, and to permit persons to whom the Software is
  15.  * furnished to do so, subject to the following conditions:
  16.  *
  17.  * The above copyright notice and this permission notice shall be included in
  18.  * all copies or substantial portions of the Software.
  19.  *
  20.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  26.  * THE SOFTWARE.
  27.  * \endparblock
  28. */
  29.  
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <dirent.h> /* For dir listing */
  34. #include <sys/ioctl.h> /* For terminal width */
  35. #include <unistd.h> /* For STDOUT_FILENO, getcwd */
  36.  
  37.  
  38. typedef struct SList List;
  39.  
  40. struct SList
  41. {
  42.   List *next;
  43.   size_t len; /**< Name length */
  44.   char name[NAME_MAX];
  45. };
  46.  
  47.  
  48. /**
  49.  * \brief Add new list node.
  50.  * \param prev Previous node.
  51.  * \returns new list node on success.
  52.  * \returns NULL on failure.
  53.  */
  54. static List*
  55. list_add (List *prev)
  56. {
  57.   static const size_t size = sizeof (List);
  58.   List *result = (List*) malloc (size);
  59.   if (result)
  60.   {
  61.     memset (result, '\0', size);
  62.     if (prev)
  63.       prev->next = result;
  64.   }
  65.   return result;
  66. }
  67.  
  68.  
  69. /**
  70.  * \brief Free list structure.
  71.  * \param head First node.
  72.  */
  73. static void
  74. list_free (List *head)
  75. {
  76.   List *target, *iterator = head;
  77.   while (iterator)
  78.   {
  79.     target = iterator;
  80.     iterator = iterator->next;
  81.     free (target);
  82.     target = NULL;
  83.   }
  84. }
  85.  
  86. /**
  87.  * \brief Wrap long output lines.
  88.  * \param width Output column width.
  89.  * \param str String.
  90.  * \param cols Columns count.
  91.  * \returns Remained string.
  92.  */
  93. void
  94. wrap (int width, const char *str, int cols)
  95. {
  96.   if (str)
  97.   {
  98.     if (cols > 1)
  99.     {
  100.       printf ("%-*s", width, str);
  101.     } /* if (cols > 1) */
  102.     else
  103.     { /* cols = 1 */
  104.       if (strlen (str) >= width)
  105.       {
  106.         char str_a[width];
  107.         strncpy (str_a, str, width-1);
  108.         str_a[width-1] = '\0';
  109.         printf ("%s\n", str_a);
  110.         wrap (width, str+width-1, cols);
  111.       }
  112.       else
  113.       {
  114.         printf ("%s", str);
  115.       }
  116.     } /* else : if (cols > 1) */
  117.   } /* if (str) */
  118. }
  119.  
  120. /**
  121.  * \brief Output directory listing.
  122.  * \param dirpath Directory path.
  123.  */
  124. void
  125. listdir (char *dirpath)
  126. {
  127.   DIR *dp;
  128.   struct dirent *entry;
  129.   List *list_head = NULL, *list_tail = NULL;
  130.   int count = 1, maxlen;
  131.  
  132.   /* Try to open dirpath */
  133.   if (! (dp = opendir (dirpath)))
  134.   {
  135.     perror("Error");
  136.     return;
  137.   }
  138.  
  139.   /* Init head */
  140.   entry = readdir (dp);
  141.   list_head = list_add (NULL);
  142.   strcpy (list_head->name, entry->d_name);
  143.   maxlen = list_head->len = strlen (list_head->name);
  144.  
  145.   list_tail = list_head;
  146.  
  147.   /* Fill dir listing */
  148.   while ( (entry = readdir (dp)))
  149.   {
  150.     count++;
  151.     list_tail = list_add (list_tail);
  152.     strcpy (list_tail->name, entry->d_name);
  153.     list_tail->len = strlen (list_tail->name);
  154.     if (list_tail->len > maxlen)
  155.       maxlen = list_tail->len;
  156.   }
  157.  
  158.   /* Fill quick access array */
  159.   List *listdir[count], *iterator;
  160.   int i;
  161.   for (i = 0, iterator = list_head;
  162.        iterator;
  163.        i++, iterator = iterator->next)
  164.   {
  165.     listdir[i] = iterator;
  166.   }
  167.  
  168.   /* Get terminal params */
  169.   struct winsize ws;
  170.   ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws);
  171.  
  172.   /* Calculating columns */
  173.   const maxcolw = ws.ws_col / 2; /* Minimal width of column is 2 */
  174.   int colw[maxcolw], next_colw[maxcolw];
  175.   int maxtotalw, totalw;
  176.   int col_count, row_count;
  177.   int next_col_count = 1, next_row_count = count;
  178.   for (i = 0; (i < maxcolw) && (i < count); i++)
  179.     next_colw[i] = maxlen + 1;
  180.   do
  181.   {
  182.     /* assign prev iteration to final vars */
  183.     col_count = next_col_count;
  184.     row_count = next_row_count;
  185.     int i;
  186.     for (i = 0; i < col_count; i++)
  187.     {
  188.       colw[i] = next_colw[i];
  189.     }
  190.     /* trying next iteration */
  191.     next_col_count++;
  192.     next_row_count = count / next_col_count;
  193.     int row, col, idx;
  194.     maxtotalw = 0;
  195.     /*for (col = 0; col < next_col_count; col++)
  196.       next_colw[col] = 2;*/
  197.     for (row = 0; row < next_row_count; row++)
  198.     {
  199.       totalw = 0;
  200.       for (col = 0; col < next_col_count; col++)
  201.       {
  202.         if (count <= (idx = row + col * next_row_count))
  203.           continue;        
  204.         if (next_colw[col] < (listdir[idx]->len + 1))
  205.           next_colw[col] = listdir[idx]->len + 1;
  206.         totalw += next_colw[col];
  207.       } /* for col */
  208.       if (maxtotalw < totalw)
  209.         maxtotalw = totalw;
  210.     } /* for row */
  211.   } while ((maxtotalw < ws.ws_col) && (col_count < count));
  212.  
  213.   /* Output */
  214.   int row, col, idx;
  215.   for (row = 0; row < row_count; row++)
  216.   {
  217.     for (col = 0; col < col_count; col++)
  218.     {
  219.       if (count <= (idx = row + col * row_count))
  220.         continue; /* check for overflow */
  221.       wrap(colw[col], listdir[idx]->name, col_count);
  222.     } /* for col */
  223.     printf("\n");
  224.   } /* for row */
  225.  
  226.   /* Clean up */
  227.   list_free (list_head);
  228.   closedir (dp);
  229. }
  230.  
  231.  
  232. int
  233. main (int argc, char *argv[])
  234. {
  235.   if (argc < 2) /* No directories specified */
  236.   {
  237.     char *cwd = NULL; /* Current Working Directory */
  238.     cwd = getcwd(NULL, 0);
  239.     printf ("%s\n", cwd);
  240.     listdir (cwd);
  241.     free (cwd);
  242.     printf ("\n");
  243.   } /* if */
  244.   else
  245.   {
  246.     int i;
  247.     for (i = 1; i < argc; i++)
  248.     {
  249.       printf ("%s\n", argv[i]);
  250.       listdir (argv[i]);
  251.       printf ("\n");
  252.     } /* for */
  253.   } /* else */
  254.  
  255.   return EXIT_SUCCESS;
  256. }
Advertisement
Add Comment
Please, Sign In to add comment