/* * \brief Utility for safely writing multi-line text * \author Norman Feske * \date 2014-01-11 */ /* * Copyright (C) 2014-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _INCLUDE__UTIL__PRINT_LINES_H_ #define _INCLUDE__UTIL__PRINT_LINES_H_ #include namespace Genode { template 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 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 line_len = 0; size_t skip_char = 1; for (; line_len < len; line_len++) { if (string[line_len] == '\0' || string[line_len] == '\n') { line_len++; break; } if (line_len == MAX_LINE_LEN) { skip_char = 0; break; } } if (!line_len) break; /* buffer for sub-string of the input string plus null-termination */ char line_buf[MAX_LINE_LEN + 1]; /* give strncpy one more as it will add the null termination */ Genode::strncpy(line_buf, string, line_len - skip_char + 1); /* process null-terminated string in buffer */ func(line_buf); /* move forward to the next sub-string to process */ string += line_len; len -= line_len; } } #endif /* _INCLUDE__UTIL__PRINT_LINES_H_ */