os: add print_lines utility

The code originates from the report_rom server. This patch makes the
code easy to reuse in other components.
This commit is contained in:
Norman Feske 2015-09-22 11:05:45 +02:00 committed by Christian Helmuth
parent 32a227ce77
commit c8ec7b6ffb
2 changed files with 104 additions and 46 deletions

View File

@ -0,0 +1,96 @@
/*
* \brief Utility for safely writing multi-line text
* \author Norman Feske
* \date 2014-01-11
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__OS__PRINT_LINES_H_
#define _INCLUDE__OS__PRINT_LINES_H_
#include <util/string.h>
namespace Genode {
template <size_t, typename FUNC>
static inline void print_lines(char const *, size_t, FUNC const &);
}
/**
* Print multi-line string
*
* \param MAX_LINE_LEN maximum line length, used to dimension a line buffer
* on the stack
* \param string character buffer, not necessarily null-terminated
* \param len number of characters to print
* \param func functor called for each line with 'char const *' as
* argument
*
* In situations where a string is supplied by an untrusted client, we cannot
* simply print the client-provided content as a single string becausewe cannot
* expect the client to null-terminate the string properly. The 'Log_multiline'
* class outputs the content line by line while keeping track of the content
* size.
*
* The output stops when reaching the end of the buffer or when a null
* character is encountered.
*/
template <Genode::size_t MAX_LINE_LEN, typename FUNC>
void Genode::print_lines(char const *string, size_t len, FUNC const &func)
{
/* skip leading line breaks */
for (; *string == '\n'; string++);
/* number of space and tab characters used for indentation */
size_t const num_indent_chars =
({
size_t n = 0;
for (; string[n] == ' ' || string[n] == '\t'; n++);
n;
});
char const * const first_line = string;
while (*string && len) {
/*
* Skip indentation if the pattern is the same as for the first line.
*/
if (Genode::strcmp(first_line, string, num_indent_chars) == 0)
string += num_indent_chars;
size_t const line_len =
({
size_t i = 0;
for (; string[i] && i < len && string[i] != '\n'; i++);
/* the newline character belongs to the line */
if (string[i] == '\n')
i++;
i;
});
if (!line_len)
break;
/*
* Copy line from (untrusted) caller to local line buffer
*/
char line_buf[MAX_LINE_LEN];
Genode::strncpy(line_buf, string, Genode::min(line_len + 1, sizeof(line_buf)));
func(line_buf);
string += line_len;
len -= line_len;
}
}
#endif /* _INCLUDE__OS__PRINT_LINES_H_ */

View File

@ -18,6 +18,7 @@
#include <util/arg_string.h>
#include <report_session/report_session.h>
#include <root/component.h>
#include <os/print_lines.h>
/* local includes */
#include <rom_registry.h>
@ -41,18 +42,6 @@ struct Report::Session_component : Genode::Rpc_object<Session>, Rom::Writer
bool &_verbose;
size_t const _str_line_end(char const * const str, size_t const len)
{
size_t i = 0;
for (; str[i] && i < len && str[i] != '\n'; i++);
/* the newline character belongs to the line */
if (str[i] == '\n')
i++;
return i;
}
Rom::Module &_create_module(Rom::Module::Name const &name)
{
try {
@ -62,6 +51,12 @@ struct Report::Session_component : Genode::Rpc_object<Session>, Rom::Writer
}
}
static void _log_lines(char const *string, size_t len)
{
Genode::print_lines<200>(string, len,
[&] (char const *line) { PLOG(" %s", line); });
}
public:
Session_component(Rom::Module::Name const &name, size_t buffer_size,
@ -91,41 +86,8 @@ struct Report::Session_component : Genode::Rpc_object<Session>, Rom::Writer
length = Genode::min(length, _ds.size());
if (_verbose) {
PLOG("report '%s'", _module.name().string());
/*
* We cannot simply print the content of the report dataspace
* as one string because we cannot expect the client to null-
* terminate the content properly. Therefore, we output the
* report line by line while keeping track of the dataspace
* size.
*/
/* pointer and length of remaining string */
char const *str = _ds.local_addr<char>();
size_t len = length;
while (*str && len) {
size_t const line_len = _str_line_end(str, len);
if (!line_len)
break;
/*
* Copy line from (untrusted) report dataspace to local
* line buffer,
*/
char line_buf[200];
Genode::strncpy(line_buf, str, Genode::min(line_len, sizeof(line_buf)));
PLOG(" %s", line_buf);
str += line_len;
len -= line_len;
}
PLOG("\n");
_log_lines(_ds.local_addr<char>(), length);
}
_module.write_content(_ds.local_addr<char>(), length);