mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 06:07:59 +00:00
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:
parent
32a227ce77
commit
c8ec7b6ffb
96
repos/os/include/util/print_lines.h
Normal file
96
repos/os/include/util/print_lines.h
Normal 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_ */
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user