This patch fixes a number of problems in the cat app. Most
importantly, it correctly displays characters at the end of the read
buffer, where previously multibyte characters were being rendered as
U_SPECIAL. It also implements the buffer size argument (-b) that the
--help mentions. The size of the buffer must be at least 4 though in
order to accommodate multibyte characters. Finally head (-H) and tail
(-t) were implemented as per --help.

If head and tail are used at the same time, the result of the first
argument is fed into the second, so "cat -H 262 -t 4 textdemo" and
"cat -t 334 -H 4 textdemo" will both show the word "brew". In the
first example, the first (head) 262 bytes are read and the last (tail)
4 of those 262 are displayed. In the second example, the last (tail)
334 bytes are read and the first (head) 4 of those 334 bytes are
displayed. Using just head or just tail works as you would expect it
to.

Oh, and I also made the hex (-x) output a little bit prettier.

I am submitting this as part of my GSoC application [GSoC 2012 - UDF
1.02 Implementation], and will most likely also be submitting patches
more related to my GSoC topic.

I had a few questions while I was writing this that I thought I might
ask. The first is, is there a way to easily test an app without
rebooting qemu? Maybe a separate filesystem containing the app that
can be mounted? Or an ftp transfer? Also, is there any way to scroll
up a console session? For example in Linux, pressing shift+page up.
Also, how do you change from the kernel console back to a virtual
console? Pressing the F1-11 buttons? (I need a new keyboard, the F
buttons don't always work).

Thanks for reading, please let me know what you think of the patch.

Taylor Killian
=== modified file 'uspace/app/bdsh/cmds/modules/cat/cat.c'
--- uspace/app/bdsh/cmds/modules/cat/cat.c	2011-09-09 15:46:21 +0000
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	2012-03-25 21:38:50 +0000
@@ -51,8 +51,8 @@
 static const char *cmdname = "cat";
 #define CAT_VERSION "0.0.1"
 #define CAT_DEFAULT_BUFLEN 1024
+#define CAT_FULL_FILE 0
 
-static const char *cat_oops = "That option is not yet supported\n";
 static const char *hexchars = "0123456789abcdef";
 
 static bool paging_enabled = false;
@@ -162,12 +162,13 @@
 	}
 }
 
-static unsigned int cat_file(const char *fname, size_t blen, bool hex)
+static unsigned int cat_file(const char *fname, size_t blen, bool hex, off64_t head, off64_t tail, bool tailFirst)
 {
 	int fd, bytes = 0, count = 0, reads = 0;
 	char *buff = NULL;
 	int i;
-	size_t offset = 0;
+	size_t offset = 0, copiedBytes = 0;
+	off64_t fileSize = 0, length = 0;
 
 	fd = open(fname, O_RDONLY);
 	if (fd < 0) {
@@ -182,30 +183,64 @@
 		return 1;
 	}
 
+	if(tail != CAT_FULL_FILE) {
+		fileSize = lseek(fd, 0, SEEK_END);
+		if(head == CAT_FULL_FILE) {
+			head = fileSize;
+			length = tail;
+		} else if (tailFirst) {
+			length = head;
+		} else {
+			if(tail > head)
+				tail = head;
+			length = tail;
+		}
+
+		if(tailFirst) {
+			lseek(fd, (tail >= fileSize) ? 0 : (fileSize - tail), SEEK_SET);
+		} else {
+			lseek(fd, ((head - tail) >= fileSize) ? 0 : (head - tail), SEEK_SET);
+		}
+	} else
+		length = head;
+
 	do {
-		bytes = read(fd, buff, blen);
+		bytes = read(fd, buff + copiedBytes, (
+			(length != CAT_FULL_FILE && length - (off64_t)count <= (off64_t)(blen - copiedBytes)) ?
+			(size_t)(length - count) :
+			(blen - copiedBytes) ) );
+		bytes += copiedBytes;
+		copiedBytes = 0;
+
 		if (bytes > 0) {
-			count += bytes;
 			buff[bytes] = '\0';
 			offset = 0;
 			for (i = 0; i < bytes && !should_quit; i++) {
 				if (hex) {
 					paged_char(hexchars[((uint8_t)buff[i])/16]);
 					paged_char(hexchars[((uint8_t)buff[i])%16]);
+					paged_char(((count+i+1) & 0xf) == 0 ? '\n' : ' ');
 				}
 				else {
 					wchar_t c = str_decode(buff, &offset, bytes);
 					if (c == 0) {
 						/* Reached end of string */
 						break;
+					} else if (c == U_SPECIAL && offset + 2 >= (size_t)bytes) {
+						/* If an extended character is cut off due to the size of the buffer,
+						   we will copy it over to the next buffer so it can be read correctly. */
+						copiedBytes = bytes - offset + 1;
+						memcpy(buff, buff + offset - 1, copiedBytes);
+						break;
 					}
 					paged_char(c);
 				}
 				
 			}
+			count += bytes;
 			reads++;
 		}
-	} while (bytes > 0 && !should_quit);
+	} while (bytes > 0 && !should_quit && (count < length || length == CAT_FULL_FILE));
 
 	close(fd);
 	if (bytes == -1) {
@@ -224,8 +259,10 @@
 {
 	unsigned int argc, i, ret = 0, buffer = 0;
 	int c, opt_ind;
+	off64_t head = CAT_FULL_FILE, tail = CAT_FULL_FILE;
 	bool hex = false;
 	bool more = false;
+	bool tailFirst = false;
 	sysarg_t rows, cols;
 	int rc;
 	
@@ -253,13 +290,24 @@
 			printf("%s\n", CAT_VERSION);
 			return CMD_SUCCESS;
 		case 'H':
-			printf("%s", cat_oops);
-			return CMD_FAILURE;
+			if(!optarg || str_uint64(optarg, NULL, 10, false, (uint64_t *)&head) != EOK ){
+				puts("Invalid head size\n");
+				return CMD_FAILURE;
+			}
+			break;
 		case 't':
-			printf("%s", cat_oops);
-			return CMD_FAILURE;
+			if(!optarg || str_uint64(optarg, NULL, 10, false, (uint64_t *)&tail) != EOK ){
+				puts("Invalid tail size\n");
+				return CMD_FAILURE;
+			}
+			if(head == CAT_FULL_FILE)
+				tailFirst = true;
+			break;
 		case 'b':
-			printf("%s", cat_oops);
+			if(!optarg || str_size_t(optarg, NULL, 10, false, &buffer) != EOK ){
+				puts("Invalid buffer size\n");
+				return CMD_FAILURE;
+			}
 			break;
 		case 'm':
 			more = true;
@@ -278,7 +326,7 @@
 		return CMD_FAILURE;
 	}
 
-	if (buffer <= 0)
+	if (buffer < 4)
 		buffer = CAT_DEFAULT_BUFLEN;
 	
 	if (more) {
@@ -294,7 +342,7 @@
 	}
 
 	for (i = optind; argv[i] != NULL && !should_quit; i++)
-		ret += cat_file(argv[i], buffer, hex);
+		ret += cat_file(argv[i], buffer, hex, head, tail, tailFirst);
 
 	if (ret)
 		return CMD_FAILURE;

=== modified file 'uspace/app/bdsh/cmds/modules/cat/cat.h'
--- uspace/app/bdsh/cmds/modules/cat/cat.h	2011-05-01 19:34:26 +0000
+++ uspace/app/bdsh/cmds/modules/cat/cat.h	2012-03-25 19:56:04 +0000
@@ -3,7 +3,7 @@
 
 /* Prototypes for the cat command, excluding entry points */
 
-static unsigned int cat_file(const char *, size_t, bool);
+static unsigned int cat_file(const char *, size_t, bool, off64_t, off64_t, bool);
 
 #endif /* CAT_H */
 

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

Reply via email to