2015-09-22 09:05:45 +00:00
|
|
|
/*
|
|
|
|
* \brief Utility for safely writing multi-line text
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2014-01-11
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 12:23:52 +00:00
|
|
|
* Copyright (C) 2014-2017 Genode Labs GmbH
|
2015-09-22 09:05:45 +00:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 12:23:52 +00:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2015-09-22 09:05:45 +00:00
|
|
|
*/
|
|
|
|
|
2016-04-26 17:09:29 +00:00
|
|
|
#ifndef _INCLUDE__UTIL__PRINT_LINES_H_
|
|
|
|
#define _INCLUDE__UTIL__PRINT_LINES_H_
|
2015-09-22 09:05:45 +00:00
|
|
|
|
|
|
|
#include <util/string.h>
|
|
|
|
|
|
|
|
namespace Genode {
|
|
|
|
|
2024-05-22 14:35:38 +00:00
|
|
|
template <size_t>
|
|
|
|
static inline void print_lines(char const *, size_t, auto const &);
|
2015-09-22 09:05:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2024-05-22 14:35:38 +00:00
|
|
|
* \param fn functor called for each line with 'char const *' as
|
2015-09-22 09:05:45 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2024-05-22 14:35:38 +00:00
|
|
|
template <Genode::size_t MAX_LINE_LEN>
|
|
|
|
void Genode::print_lines(char const *string, size_t len, auto const &fn)
|
2015-09-22 09:05:45 +00:00
|
|
|
{
|
|
|
|
/* 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;
|
|
|
|
|
2019-06-18 18:57:44 +00:00
|
|
|
size_t line_len = 0;
|
2023-08-22 08:48:38 +00:00
|
|
|
size_t skip_char = 0;
|
2019-06-18 18:57:44 +00:00
|
|
|
|
|
|
|
for (; line_len < len; line_len++) {
|
|
|
|
if (string[line_len] == '\0' || string[line_len] == '\n') {
|
|
|
|
line_len++;
|
2023-08-22 08:48:38 +00:00
|
|
|
skip_char = 1;
|
2019-06-18 18:57:44 +00:00
|
|
|
break;
|
|
|
|
}
|
2023-08-22 08:48:38 +00:00
|
|
|
if (line_len == MAX_LINE_LEN)
|
2019-06-18 18:57:44 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-09-22 09:05:45 +00:00
|
|
|
|
|
|
|
if (!line_len)
|
|
|
|
break;
|
|
|
|
|
2019-06-18 18:57:44 +00:00
|
|
|
/* buffer for sub-string of the input string plus null-termination */
|
|
|
|
char line_buf[MAX_LINE_LEN + 1];
|
|
|
|
|
2020-05-11 14:10:27 +00:00
|
|
|
/* one more byte for the null termination */
|
|
|
|
copy_cstring(line_buf, string, line_len - skip_char + 1);
|
2019-06-18 18:57:44 +00:00
|
|
|
|
|
|
|
/* process null-terminated string in buffer */
|
2024-05-22 14:35:38 +00:00
|
|
|
fn(line_buf);
|
2015-09-22 09:05:45 +00:00
|
|
|
|
2019-06-18 18:57:44 +00:00
|
|
|
/* move forward to the next sub-string to process */
|
2015-09-22 09:05:45 +00:00
|
|
|
string += line_len;
|
|
|
|
len -= line_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-26 17:09:29 +00:00
|
|
|
#endif /* _INCLUDE__UTIL__PRINT_LINES_H_ */
|