[libc-trusty] Add line buffering to fputc/fputs/fprintf.

Change-Id: I5122d632fe80648004a78c42015ece4da5cf8834
diff --git a/lib/libc-trusty/stdio.c b/lib/libc-trusty/stdio.c
index ece0d3b..2ec670e 100644
--- a/lib/libc-trusty/stdio.c
+++ b/lib/libc-trusty/stdio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013-2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,20 +18,64 @@
 #include <stdio.h>
 #include <string.h>
 #include <trusty_std.h>
+#include <err.h>
+
+#define LINE_BUFFER_SIZE 128
+
+struct file_buffer {
+	char data[LINE_BUFFER_SIZE];
+	size_t pos;
+};
+
+struct file_context {
+	int fd;
+	struct file_buffer *buffer;
+};
+
+static int buffered_put(struct file_buffer *buffer, int fd, char c)
+{
+	int result = 0;
+
+	buffer->data[buffer->pos++] = c;
+	if (buffer->pos == sizeof(buffer->data) || c == '\n') {
+		result = write(fd, buffer->data, buffer->pos);
+		buffer->pos = 0;
+	}
+	return result;
+}
+
+static int buffered_write(struct file_context *ctx, const char *str, size_t sz)
+{
+	unsigned i;
+
+	if (!ctx->buffer) {
+		return ERR_INVALID_ARGS;
+	}
+
+	for (i = 0; i < sz; i++) {
+		int result = buffered_put(ctx->buffer, ctx->fd, str[i]);
+		if (result < 0) {
+			return result;
+		}
+	}
+
+	return sz;
+}
 
 static int _stdio_fputc(void *ctx, int c)
 {
-	int fd = (int)ctx;
+	struct file_context *fctx = (struct file_context*)ctx;
 	char _c = (char)c;
 
-	write(fd, &_c, 1);
+	buffered_put(fctx->buffer, fctx->fd, c);
 	return INT_MAX;
 }
 
 static int _stdio_fputs(void *ctx, const char *s)
 {
-	int fd = (int)ctx;
-	return write(fd, (char *)s, strlen(s));
+	struct file_context *fctx = (struct file_context*)ctx;
+
+	return buffered_write(fctx, s, strlen(s));
 }
 
 static int _stdio_fgetc(void *ctx)
@@ -41,8 +85,9 @@
 
 static int _output_func(const char *str, size_t len, void *state)
 {
-	int fd = (int)state;
-	return write(fd, (char *)str, strnlen(str, len));
+	struct file_context *ctx = (struct file_context*)state;
+
+	return buffered_write(ctx, str, strnlen(str, len));
 }
 
 static int _stdio_vfprintf(void *ctx, const char *fmt, va_list ap)
@@ -50,9 +95,17 @@
 	return _printf_engine(_output_func, ctx, fmt, ap);
 }
 
-#define DEFINE_STDIO_DESC(id)					\
-	[(id)]	= {						\
-		.ctx		= (void *)(id),			\
+struct file_buffer stdout_buffer = {.pos = 0};
+struct file_buffer stderr_buffer = {.pos = 0};
+struct file_context fctx[3] = {
+	{.fd = 0, .buffer = NULL},
+	{.fd = 1, .buffer = &stdout_buffer },
+	{.fd = 2, .buffer = &stderr_buffer }
+};
+
+#define DEFINE_STDIO_DESC(fctx)					\
+	{							\
+		.ctx		= (void *)(fctx),		\
 		.fputc		= _stdio_fputc,			\
 		.fputs		= _stdio_fputs,			\
 		.fgetc		= _stdio_fgetc,			\
@@ -60,9 +113,9 @@
 	}
 
 FILE __stdio_FILEs[3] = {
-	DEFINE_STDIO_DESC(0), /* stdin */
-	DEFINE_STDIO_DESC(1), /* stdout */
-	DEFINE_STDIO_DESC(2), /* stderr */
+	DEFINE_STDIO_DESC(&fctx[0]), /* stdin */
+	DEFINE_STDIO_DESC(&fctx[1]), /* stdout */
+	DEFINE_STDIO_DESC(&fctx[2]), /* stderr */
 };
 #undef DEFINE_STDIO_DESC