genode/repos/base/include/util/print_lines.h
2017-02-23 15:03:29 +01:00

97 lines
2.5 KiB
C++

/*
* \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__UTIL__PRINT_LINES_H_
#define _INCLUDE__UTIL__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, sizeof(line_buf)));
func(line_buf);
string += line_len;
len -= line_len;
}
}
#endif /* _INCLUDE__UTIL__PRINT_LINES_H_ */