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