Index: uspace/app/bdsh/cmds/modules/ls/ls.c
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.c	(revision 73aec008f71d2837377d9654ab5e73c252ba6806)
+++ uspace/app/bdsh/cmds/modules/ls/ls.c	(revision a30e4354a9608d1a27fa141c8d89409ef2d9aae8)
@@ -38,7 +38,9 @@
 #include <dirent.h>
 #include <fcntl.h>
+#include <getopt.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <str.h>
+#include <sort.h>
 
 #include "errors.h"
@@ -51,9 +53,60 @@
 static const char *cmdname = "ls";
 
-static void ls_scan_dir(const char *d, DIR *dirp)
-{
-	struct dirent *dp;
-	char *buff;
-
+static struct option const long_options[] = {
+	{ "help", no_argument, 0, 'h' },
+	{ "unsort", no_argument, 0, 'u' },	
+	{ 0, 0, 0, 0 }
+};
+
+/** Compare 2 directory elements.
+ *
+ * It compares 2 elements of a directory : a file is considered
+ * as lower than a directory, and if they have the same type,
+ * they are compared alphabetically.
+ *
+ * @param a		Pointer to the structure of the first element.
+ * @param b		Pointer to the structure of the second element.
+ * @param arg	Pointer for an other and optionnal argument.
+ *
+ * @return		-1 if a < b,
+ *				1 otherwise.
+ */
+static int ls_cmp(void *a, void *b, void *arg)
+{
+	int a_isdir = (*((struct dir_elem_t *)a)).isdir;
+	char * a_name = (*((struct dir_elem_t *)a)).name;
+	
+	int b_isdir = (*((struct dir_elem_t *)b)).isdir;
+	char * b_name = (*((struct dir_elem_t *)b)).name;
+	
+	if ((!a_isdir && b_isdir)
+		|| (((!b_isdir && !a_isdir) || (b_isdir && a_isdir))
+		&& str_cmp(a_name, b_name) < 0))
+		return -1;
+	else
+		return 1;
+}
+
+/** Scan a directory.
+ *
+ * Scan the content of a directory and print it.
+ *
+ * @param d		Name of the directory.
+ * @param dirp	Directory stream.
+ * @param sort	1 if the output must be sorted,
+ *				0 otherwise.
+ */
+static void ls_scan_dir(const char *d, DIR *dirp, int sort)
+{
+	int alloc_blocks = 20;
+	int i = 0;
+	int nbdirs = 0;
+	int rc = 0;
+	char * buff = NULL;
+	struct dir_elem_t * tmp = NULL;
+	struct dir_elem_t * tosort = NULL;
+	struct dirent * dp = NULL;
+	struct stat s;
+	
 	if (! dirp)
 		return;
@@ -64,13 +117,97 @@
 		return;
 	}
-
+	memset(buff, 0, sizeof(buff));
+	
+	if (!sort) {
+		while ((dp = readdir(dirp))) {
+			memset(buff, 0, sizeof(buff));
+			/* Don't worry if inserting a double slash, this will be fixed by
+			 * absolutize() later with subsequent calls to open() or readdir() */
+			snprintf(buff, PATH_MAX - 1, "%s/%s", d, dp->d_name);
+			ls_print(dp->d_name, buff);
+		}
+
+		free(buff);
+
+		return;
+	}
+	
+	tosort = (struct dir_elem_t *)malloc(alloc_blocks*sizeof(struct dir_elem_t));
+	if (NULL == tosort) {
+		cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
+		free(buff);
+		return;
+	}
+	memset(tosort, 0, sizeof(tosort));
+	
 	while ((dp = readdir(dirp))) {
+		nbdirs++;
+		
+		if (nbdirs > alloc_blocks) {
+			alloc_blocks += alloc_blocks;
+			
+			tmp = (struct dir_elem_t *)realloc(tosort,
+					alloc_blocks*sizeof(struct dir_elem_t));
+			if (NULL == tmp) {
+				cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
+				for(i=0;i<(nbdirs-1);i++) {
+					free(tosort[i].name);
+				}
+				free(tosort);
+				free(buff);
+				return;
+			}
+			
+			tosort = tmp;
+		}
+		
+		// fill the name field
+		tosort[nbdirs-1].name = (char *)malloc(str_length(dp->d_name)+1);
+		if (NULL == tosort[nbdirs-1].name) {
+			cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
+			for(i=0;i<(nbdirs-1);i++) {
+				free(tosort[i].name);
+			}
+			free(tosort);
+			free(buff);
+			return;
+		}
+		
+		memset(tosort[nbdirs-1].name, 0, str_length(dp->d_name)+1);
+		str_cpy(tosort[nbdirs-1].name, str_length(dp->d_name)+1, dp->d_name);
+		
+		// fill the isdir field
+		memset(buff, 0, sizeof(buff));
+		snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[nbdirs-1].name);
+		
+		rc = stat(buff, &s);
+		if (rc != 0) {
+			printf("ls: skipping bogus node %s\n", buff);
+			printf("rc=%d\n", rc);
+			for(i=0;i<nbdirs;i++) {
+				free(tosort[i].name);
+			}
+			free(tosort);
+			free(buff);
+			return;
+		}
+		
+		tosort[nbdirs-1].isdir = s.is_directory ? 1 : 0;
+	}
+	
+	if (!qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t), ls_cmp, NULL)) {
+		printf("Sorting error.\n");
+	}
+	
+	for(i=0;i<nbdirs;i++) {
 		memset(buff, 0, sizeof(buff));
 		/* Don't worry if inserting a double slash, this will be fixed by
 		 * absolutize() later with subsequent calls to open() or readdir() */
-		snprintf(buff, PATH_MAX - 1, "%s/%s", d, dp->d_name);
-		ls_print(dp->d_name, buff);
-	}
-
+		snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[i].name);
+		ls_print(tosort[i].name, buff);
+		free(tosort[i].name);
+	}
+	
+	free(tosort);
 	free(buff);
 
@@ -78,11 +215,16 @@
 }
 
-/* ls_print currently does nothing more than print the entry.
- * in the future, we will likely pass the absolute path, and
+/** Print an entry.
+ *
+ * ls_print currently does nothing more than print the entry.
+ * In the future, we will likely pass the absolute path, and
  * some sort of ls_options structure that controls how each
  * entry is printed and what is printed about it.
  *
- * Now we just print basic DOS style lists */
-
+ * Now we just print basic DOS style lists.
+ *
+ * @param name		Name of the entry.
+ * @param pathname	Path of the entry.
+ */
 static void ls_print(const char *name, const char *pathname)
 {
@@ -114,6 +256,11 @@
 	} else {
 		help_cmd_ls(HELP_SHORT);
-		printf("  `%s' [path], if no path is given the current "
-				"working directory is used.\n", cmdname);
+		printf(
+		"Usage:  %s [options] [path]\n"
+		"If not path is given, the current working directory is used.\n"
+		"Options:\n"
+		"  -h, --help       A short option summary\n"
+		"  -u, --unsort     Do not sort directory entries\n",
+		cmdname);
 	}
 
@@ -127,7 +274,24 @@
 	char *buff;
 	DIR *dirp;
+	int c, opt_ind;
+	int sort = 1;
 
 	argc = cli_count_args(argv);
-
+	
+	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
+		c = getopt_long(argc, argv, "hu", long_options, &opt_ind);
+		switch (c) {
+		case 'h':
+			help_cmd_ls(HELP_LONG);
+			return CMD_SUCCESS;
+		case 'u':
+			sort = 0;
+			break;
+		}
+	}
+	
+	int dir = (int)argc > optind ? (int)argc-1 : optind-1;
+	argc -= (optind-1);
+	
 	buff = (char *) malloc(PATH_MAX);
 	if (NULL == buff) {
@@ -136,10 +300,10 @@
 	}
 	memset(buff, 0, sizeof(buff));
-
+	
 	if (argc == 1)
 		getcwd(buff, PATH_MAX);
 	else
-		str_cpy(buff, PATH_MAX, argv[1]);
-
+		str_cpy(buff, PATH_MAX, argv[dir]);
+	
 	if (stat(buff, &s)) {
 		cli_error(CL_ENOENT, buff);
@@ -158,5 +322,5 @@
 			return CMD_FAILURE;
 		}
-		ls_scan_dir(buff, dirp);
+		ls_scan_dir(buff, dirp, sort);
 		closedir(dirp);
 	}
Index: uspace/app/bdsh/cmds/modules/ls/ls.h
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.h	(revision 73aec008f71d2837377d9654ab5e73c252ba6806)
+++ uspace/app/bdsh/cmds/modules/ls/ls.h	(revision a30e4354a9608d1a27fa141c8d89409ef2d9aae8)
@@ -7,6 +7,16 @@
 #define LS_DIR   2
 
-static void ls_scan_dir(const char *, DIR *);
+static void ls_scan_dir(const char *, DIR *, int);
 static void ls_print(const char *, const char *);
+
+/** Structure to represent a directory entry.
+ *
+ * Useful to keep together important informations
+ * for sorting directory entries.
+ */
+struct dir_elem_t {
+	char * name;
+	int isdir;
+};
 
 #endif /* LS_H */
