Hi,

I have added --recursive (-R) option to `ls` command. I have attached the
patch for the same in this mail.

Any feedback and suggestions on improvements are very welcome.


Thanks,
Vivek Prakash
=== modified file 'uspace/app/bdsh/cmds/modules/ls/ls.c'
--- uspace/app/bdsh/cmds/modules/ls/ls.c	2011-07-19 20:04:59 +0000
+++ uspace/app/bdsh/cmds/modules/ls/ls.c	2012-03-23 20:00:28 +0000
@@ -41,35 +41,33 @@
 #include <str.h>
 #include <sort.h>
 
+#include "ls.h"
 #include "errors.h"
 #include "config.h"
 #include "util.h"
 #include "entry.h"
 #include "cmds.h"
 
-/* Various values that can be returned by ls_scope() */
-#define LS_BOGUS 0
-#define LS_FILE  1
-#define LS_DIR   2
-
-/** Structure to represent a directory entry.
- *
- * Useful to keep together important information
- * for sorting directory entries.
- */
-struct dir_elem_t {
-	char *name;
-	struct stat s;
-};
-
 static const char *cmdname = "ls";
 
+static ls_job_t ls;
+
 static struct option const long_options[] = {
 	{ "help", no_argument, 0, 'h' },
 	{ "unsort", no_argument, 0, 'u' },
+	{ "recursive", no_argument, 0, 'R' },
 	{ 0, 0, 0, 0 }
 };
 
+static unsigned int ls_start(ls_job_t *ls)
+{
+	ls->recursive = 0;
+	ls->sort = 1;
+
+	return 1;
+}
+
+
 /** Print an entry.
  *
  * ls_print currently does nothing more than print the entry.
@@ -117,6 +115,7 @@
 		return 1;
 }
 
+
 /** Scan a directory.
  *
  * Scan the content of a directory and print it.
@@ -126,7 +125,8 @@
  * @param sort	1 if the output must be sorted,
  *				0 otherwise.
  */
-static void ls_scan_dir(const char *d, DIR *dirp, int sort)
+static signed int ls_scan_dir(const char *d, DIR *dirp, 
+    struct dir_elem_t **dir_listp)
 {
 	int alloc_blocks = 20;
 	int i;
@@ -135,23 +135,23 @@
 	int len;
 	char *buff;
 	struct dir_elem_t *tmp;
-	struct dir_elem_t *tosort;
+	struct dir_elem_t *tosort, *dir_list;
 	struct dirent *dp;
 	
 	if (!dirp)
-		return;
+		return -1;
 
 	buff = (char *) malloc(PATH_MAX);
 	if (!buff) {
 		cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
-		return;
+		return -1;
 	}
 	
 	tosort = (struct dir_elem_t *) malloc(alloc_blocks * sizeof(*tosort));
 	if (!tosort) {
 		cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
 		free(buff);
-		return;
+		return -1;
 	}
 	
 	while ((dp = readdir(dirp))) {
@@ -186,7 +186,7 @@
 		}
 	}
 	
-	if (sort) {
+	if (ls.sort) {
 		if (!qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t),
 		    ls_cmp, NULL)) {
 			printf("Sorting error.\n");
@@ -195,12 +195,114 @@
 	
 	for (i = 0; i < nbdirs; i++)
 		ls_print(&tosort[i]);
+
+	/* Populate the directory list. */
+	if (ls.recursive) {
+		dir_list = *dir_listp;
+		tmp = (struct dir_elem_t *) realloc(dir_list, 
+            nbdirs * sizeof(struct dir_elem_t));
+		if (!tmp) {
+			cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
+			goto out;
+		} 
+
+		dir_list = tmp;
+		*dir_listp = dir_list;
+
+		for (i = 0; i < nbdirs; i++)
+			dir_list[i].name = str_dup(tosort[i].name);
+	}
 	
 out:
 	for(i = 0; i < nbdirs; i++)
 		free(tosort[i].name);
 	free(tosort);
 	free(buff);
+
+	return nbdirs;
+}
+
+
+/** Visit a directory recursively.
+ *
+ * ls_recursive visits all the subdirectories recursively and
+ * prints the files and directories in them.
+ *
+ * @param path	Path the current directory being visited.
+ * @param dirp	Directory stream.
+ */
+static unsigned int ls_recursive(const char *path, DIR *dirp)
+{
+	int i, nbdirs, ret;
+	unsigned int scope;
+	char *subdir_path;
+	DIR *subdirp;
+	struct dir_elem_t *dir_list;
+    
+    const char * const trailing_slash = "/";
+
+	dir_list = (struct dir_elem_t *) malloc(sizeof(struct dir_elem_t));
+
+	printf("\n%s:\n", path);
+
+	nbdirs = ls_scan_dir(path, dirp, &dir_list); 
+	if(nbdirs == -1)
+	   return CMD_FAILURE;
+
+	subdir_path = (char *) malloc(PATH_MAX);
+
+	for (i = 0; i < nbdirs; ++i) {
+		memset(subdir_path, 0, PATH_MAX);
+
+		if (str_size(subdir_path) + str_size(path) + 1 <= PATH_MAX)
+			str_append(subdir_path, PATH_MAX, path);
+		if (path[str_size(path)-1] != '/' &&
+			str_size(subdir_path) + str_size(trailing_slash) + 1 <= PATH_MAX)
+			str_append(subdir_path, PATH_MAX, trailing_slash);
+		if (str_size(subdir_path) +
+			str_size(dir_list[i].name) + 1 <= PATH_MAX)
+			str_append(subdir_path, PATH_MAX, dir_list[i].name);
+
+		scope = ls_scope(subdir_path, &dir_list[i]);
+		switch(scope) {
+			case LS_BOGUS:
+				return CMD_FAILURE;
+				break;
+			case LS_FILE:
+				break;
+			case LS_DIR:
+				subdirp = opendir(subdir_path);
+				if (!subdirp) {
+					/* May have been deleted between scoping it and 
+                     * deleting it */
+					cli_error(CL_EFAIL, "Could not stat %s", 
+                        dir_list[i].name);
+					return CMD_FAILURE;
+				}
+
+				ret = ls_recursive(subdir_path, subdirp);
+				if (ret == CMD_FAILURE)
+					return CMD_FAILURE;
+				break;
+		}
+	}
+   
+	return CMD_SUCCESS; 
+}
+
+static unsigned int ls_scope(const char *path, struct dir_elem_t *de)
+{
+	if (stat(path, &de->s)) {
+		cli_error(CL_ENOENT, path);
+		return LS_BOGUS;
+	}
+
+	if (de->s.is_file)
+		return LS_FILE;
+	else if (de->s.is_directory)
+		return LS_DIR;
+
+	return LS_BOGUS;
 }
 
 void help_cmd_ls(unsigned int level)
@@ -214,7 +316,8 @@
 		"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",
+		"  -u, --unsort     Do not sort directory entries\n"
+		"  -R, --recursive  List subdirectories recursively\n",
 		cmdname);
 	}
 
@@ -227,18 +330,27 @@
 	struct dir_elem_t de;
 	DIR *dirp;
 	int c, opt_ind;
-	int sort = 1;
+	int ret = 0;
+	unsigned int scope;
+
+	if (!ls_start(&ls)) {
+		cli_error(CL_EFAIL, "%s: Could not initialize", cmdname);
+		return CMD_FAILURE;
+	}
 
 	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);
+		c = getopt_long(argc, argv, "huR", long_options, &opt_ind);
 		switch (c) {
 		case 'h':
 			help_cmd_ls(HELP_LONG);
 			return CMD_SUCCESS;
 		case 'u':
-			sort = 0;
+			ls.sort = 0;
+			break;
+		case 'R':
+			ls.recursive = 1;
 			break;
 		}
 	}
@@ -250,35 +362,43 @@
 		cli_error(CL_ENOMEM, "%s: ", cmdname);
 		return CMD_FAILURE;
 	}
-	memset(de.name, 0, sizeof(PATH_MAX));
+	memset(de.name, 0, PATH_MAX);
 	
 	if (argc == 0)
 		getcwd(de.name, PATH_MAX);
 	else
 		str_cpy(de.name, PATH_MAX, argv[optind]);
-	
-	if (stat(de.name, &de.s)) {
-		cli_error(CL_ENOENT, de.name);
-		free(de.name);
-		return CMD_FAILURE;
-	}
 
-	if (de.s.is_file) {
-		ls_print(&de);
-	} else {
-		dirp = opendir(de.name);
-		if (!dirp) {
-			/* May have been deleted between scoping it and opening it */
-			cli_error(CL_EFAIL, "Could not stat %s", de.name);
-			free(de.name);
+	scope = ls_scope(de.name, &de);
+	switch (scope) {
+		case LS_BOGUS:
 			return CMD_FAILURE;
-		}
-		ls_scan_dir(de.name, dirp, sort);
-		closedir(dirp);
+			break;
+		case LS_FILE:
+			ls_print(&de);
+			break;
+		case LS_DIR:
+			dirp = opendir(de.name);
+			if (!dirp) {
+				/* May have been deleted between scoping it and opening it */
+				cli_error(CL_EFAIL, "Could not stat %s", de.name);
+				free(de.name);
+				return CMD_FAILURE;
+			}
+			if (ls.recursive)
+				ret = ls_recursive(de.name, dirp);
+			else  
+				ret = ls_scan_dir(de.name, dirp, NULL);
+
+			closedir(dirp);
+			break;
 	}
 
 	free(de.name);
 
-	return CMD_SUCCESS;
+	if (ret == -1 || ret == CMD_FAILURE)
+		return CMD_FAILURE;
+	else
+		return CMD_SUCCESS;
 }
 

=== added file 'uspace/app/bdsh/cmds/modules/ls/ls.h'
--- uspace/app/bdsh/cmds/modules/ls/ls.h	1970-01-01 00:00:00 +0000
+++ uspace/app/bdsh/cmds/modules/ls/ls.h	2012-03-23 19:07:30 +0000
@@ -0,0 +1,33 @@
+#ifndef LS_H
+#define LS_H
+
+/* Various values that can be returned by ls_scope() */
+#define LS_BOGUS 0
+#define LS_FILE  1
+#define LS_DIR   2
+
+typedef struct {
+	/* Options set at runtime. */
+	unsigned int recursive;
+	unsigned int sort;
+
+} ls_job_t;
+
+/** Structure to represent a directory entry.
+ *
+ * Useful to keep together important information
+ * for sorting directory entries.
+ */
+struct dir_elem_t {
+	char *name;
+	struct stat s;
+};
+
+/* Prototypes for the ls command, excluding entry points. */
+static unsigned int ls_start(ls_job_t *);
+static void ls_print(struct dir_elem_t *);
+static int ls_cmp(void *, void *, void *);
+static signed int ls_scan_dir(const char *, DIR *, struct dir_elem_t **);
+static unsigned int ls_recursive(const char *, DIR *);
+static unsigned int ls_scope(const char *, struct dir_elem_t *);
+#endif

_______________________________________________
HelenOS-devel mailing list
[email protected]
http://lists.modry.cz/cgi-bin/listinfo/helenos-devel

Reply via email to