1240116Smarcel//
2240116Smarcel// Automated Testing Framework (atf)
3240116Smarcel//
4240116Smarcel// Copyright (c) 2007 The NetBSD Foundation, Inc.
5240116Smarcel// All rights reserved.
6240116Smarcel//
7240116Smarcel// Redistribution and use in source and binary forms, with or without
8240116Smarcel// modification, are permitted provided that the following conditions
9240116Smarcel// are met:
10240116Smarcel// 1. Redistributions of source code must retain the above copyright
11240116Smarcel//    notice, this list of conditions and the following disclaimer.
12240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright
13240116Smarcel//    notice, this list of conditions and the following disclaimer in the
14240116Smarcel//    documentation and/or other materials provided with the distribution.
15240116Smarcel//
16240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28240116Smarcel//
29240116Smarcel
30240116Smarcelextern "C" {
31240116Smarcel#include <sys/ioctl.h>
32240116Smarcel
33240116Smarcel#include <termios.h>
34240116Smarcel#include <unistd.h>
35240116Smarcel}
36240116Smarcel
37240116Smarcel#include <sstream>
38240116Smarcel
39240116Smarcel#include "env.hpp"
40240116Smarcel#include "text.hpp"
41240116Smarcel#include "sanity.hpp"
42240116Smarcel#include "text.hpp"
43240116Smarcel#include "ui.hpp"
44240116Smarcel
45240116Smarcelnamespace impl = atf::ui;
46240116Smarcel#define IMPL_NAME "atf::ui"
47240116Smarcel
48240116Smarcelstatic
49240116Smarcelsize_t
50240116Smarcelterminal_width(void)
51240116Smarcel{
52240116Smarcel    static bool done = false;
53240116Smarcel    static size_t width = 0;
54240116Smarcel
55240116Smarcel    if (!done) {
56240116Smarcel        if (atf::env::has("COLUMNS")) {
57240116Smarcel            const std::string cols = atf::env::get("COLUMNS");
58240116Smarcel            if (cols.length() > 0) {
59240116Smarcel                width = atf::text::to_type< size_t >(cols);
60240116Smarcel            }
61240116Smarcel        } else {
62240116Smarcel            struct winsize ws;
63240116Smarcel            if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
64240116Smarcel                width = ws.ws_col;
65240116Smarcel        }
66240116Smarcel
67240116Smarcel        if (width >= 80)
68240116Smarcel            width -= 5;
69240116Smarcel
70240116Smarcel        done = true;
71240116Smarcel    }
72240116Smarcel
73240116Smarcel    return width;
74240116Smarcel}
75240116Smarcel
76240116Smarcelstatic
77240116Smarcelstd::string
78240116Smarcelformat_paragraph(const std::string& text,
79240116Smarcel                 const std::string& tag,
80240116Smarcel                 const bool first,
81240116Smarcel                 const bool repeat,
82240116Smarcel                 const size_t col)
83240116Smarcel{
84240116Smarcel    PRE(text.find('\n') == std::string::npos);
85240116Smarcel
86240116Smarcel    const std::string pad(col - tag.length(), ' ');
87240116Smarcel    const std::string fullpad(col, ' ');
88240116Smarcel
89240116Smarcel    std::string formatted;
90240116Smarcel    if (first || repeat)
91240116Smarcel        formatted = tag + pad;
92240116Smarcel    else
93240116Smarcel        formatted = fullpad;
94240116Smarcel    INV(formatted.length() == col);
95240116Smarcel    size_t curcol = col;
96240116Smarcel
97240116Smarcel    const size_t maxcol = terminal_width();
98240116Smarcel
99240116Smarcel    std::vector< std::string > words = atf::text::split(text, " ");
100240116Smarcel    for (std::vector< std::string >::const_iterator iter = words.begin();
101240116Smarcel         iter != words.end(); iter++) {
102240116Smarcel        const std::string& word = *iter;
103240116Smarcel
104240116Smarcel        if (iter != words.begin() && maxcol > 0 &&
105240116Smarcel            curcol + word.length() + 1 > maxcol) {
106240116Smarcel            if (repeat)
107240116Smarcel                formatted += '\n' + tag + pad;
108240116Smarcel            else
109240116Smarcel                formatted += '\n' + fullpad;
110240116Smarcel            curcol = col;
111240116Smarcel        } else if (iter != words.begin()) {
112240116Smarcel            formatted += ' ';
113240116Smarcel            curcol++;
114240116Smarcel        }
115240116Smarcel
116240116Smarcel        formatted += word;
117240116Smarcel        curcol += word.length();
118240116Smarcel    }
119240116Smarcel
120240116Smarcel    return formatted;
121240116Smarcel}
122240116Smarcel
123240116Smarcelstd::string
124240116Smarcelimpl::format_error(const std::string& prog_name, const std::string& error)
125240116Smarcel{
126240116Smarcel    return format_text_with_tag("ERROR: " + error, prog_name + ": ", true);
127240116Smarcel}
128240116Smarcel
129240116Smarcelstd::string
130240116Smarcelimpl::format_info(const std::string& prog_name, const std::string& msg)
131240116Smarcel{
132240116Smarcel    return format_text_with_tag(msg, prog_name + ": ", true);
133240116Smarcel}
134240116Smarcel
135240116Smarcelstd::string
136240116Smarcelimpl::format_text(const std::string& text)
137240116Smarcel{
138240116Smarcel    return format_text_with_tag(text, "", false, 0);
139240116Smarcel}
140240116Smarcel
141240116Smarcelstd::string
142240116Smarcelimpl::format_text_with_tag(const std::string& text, const std::string& tag,
143240116Smarcel                           bool repeat, size_t col)
144240116Smarcel{
145240116Smarcel    PRE(col == 0 || col >= tag.length());
146240116Smarcel    if (col == 0)
147240116Smarcel        col = tag.length();
148240116Smarcel
149240116Smarcel    std::string formatted;
150240116Smarcel
151240116Smarcel    std::vector< std::string > lines = atf::text::split(text, "\n");
152240116Smarcel    for (std::vector< std::string >::const_iterator iter = lines.begin();
153240116Smarcel         iter != lines.end(); iter++) {
154240116Smarcel        const std::string& line = *iter;
155240116Smarcel
156240116Smarcel        formatted += format_paragraph(line, tag, iter == lines.begin(),
157240116Smarcel                                      repeat, col);
158240116Smarcel        if (iter + 1 != lines.end()) {
159240116Smarcel            if (repeat)
160240116Smarcel                formatted += "\n" + tag + "\n";
161240116Smarcel            else
162240116Smarcel                formatted += "\n\n";
163240116Smarcel        }
164240116Smarcel    }
165240116Smarcel
166240116Smarcel    return formatted;
167240116Smarcel}
168240116Smarcel
169240116Smarcelstd::string
170240116Smarcelimpl::format_warning(const std::string& prog_name, const std::string& error)
171240116Smarcel{
172240116Smarcel    return format_text_with_tag("WARNING: " + error, prog_name + ": ", true);
173240116Smarcel}
174