CMake/Source/CursesDialog/cmCursesLongMessageForm.cxx
Brad King b6d116e240 cmCursesLongMessageForm: Avoid -Wstringop-overflow warning
We use `strncpy` to copy the title up to a maximum number of
characters.  GCC 8's `-Wstringop-overflow` warns that the length
depends on the input length because it fails to recognize that we
are bounding it to the buffer size too.  Update the code to hide
the dependence on the input length.
2018-07-31 08:52:59 -04:00

179 lines
4.1 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCursesLongMessageForm.h"
#include "cmCursesForm.h"
#include "cmCursesMainForm.h"
#include "cmCursesStandardIncludes.h"
#include "cmVersion.h"
#include <stdio.h>
#include <string.h>
inline int ctrl(int z)
{
return (z & 037);
}
cmCursesLongMessageForm::cmCursesLongMessageForm(
std::vector<std::string> const& messages, const char* title)
{
// Append all messages into on big string
std::vector<std::string>::const_iterator it;
for (it = messages.begin(); it != messages.end(); it++) {
this->Messages += (*it);
// Add one blank line after each message
this->Messages += "\n\n";
}
this->Title = title;
this->Fields[0] = nullptr;
this->Fields[1] = nullptr;
}
cmCursesLongMessageForm::~cmCursesLongMessageForm()
{
if (this->Fields[0]) {
free_field(this->Fields[0]);
}
}
void cmCursesLongMessageForm::UpdateStatusBar()
{
int x, y;
getmaxyx(stdscr, y, x);
char bar[cmCursesMainForm::MAX_WIDTH];
size_t size = this->Title.size();
if (size >= cmCursesMainForm::MAX_WIDTH) {
size = cmCursesMainForm::MAX_WIDTH - 1;
}
strncpy(bar, this->Title.c_str(), size);
for (size_t i = size - 1; i < cmCursesMainForm::MAX_WIDTH; i++) {
bar[i] = ' ';
}
int width;
if (x < cmCursesMainForm::MAX_WIDTH) {
width = x;
} else {
width = cmCursesMainForm::MAX_WIDTH - 1;
}
bar[width] = '\0';
char version[cmCursesMainForm::MAX_WIDTH];
char vertmp[128];
sprintf(vertmp, "CMake Version %s", cmVersion::GetCMakeVersion());
size_t sideSpace = (width - strlen(vertmp));
for (size_t i = 0; i < sideSpace; i++) {
version[i] = ' ';
}
sprintf(version + sideSpace, "%s", vertmp);
version[width] = '\0';
char fmt_s[] = "%s";
curses_move(y - 4, 0);
attron(A_STANDOUT);
printw(fmt_s, bar);
attroff(A_STANDOUT);
curses_move(y - 3, 0);
printw(fmt_s, version);
pos_form_cursor(this->Form);
}
void cmCursesLongMessageForm::PrintKeys()
{
int x, y;
getmaxyx(stdscr, y, x);
if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
return;
}
char firstLine[512];
sprintf(firstLine, "Press [e] to exit help");
char fmt_s[] = "%s";
curses_move(y - 2, 0);
printw(fmt_s, firstLine);
pos_form_cursor(this->Form);
}
void cmCursesLongMessageForm::Render(int /*left*/, int /*top*/, int /*width*/,
int /*height*/)
{
int x, y;
getmaxyx(stdscr, y, x);
if (this->Form) {
unpost_form(this->Form);
free_form(this->Form);
this->Form = nullptr;
}
const char* msg = this->Messages.c_str();
curses_clear();
if (this->Fields[0]) {
free_field(this->Fields[0]);
this->Fields[0] = nullptr;
}
this->Fields[0] = new_field(y - 6, x - 2, 1, 1, 0, 0);
field_opts_off(this->Fields[0], O_STATIC);
this->Form = new_form(this->Fields);
post_form(this->Form);
int i = 0;
form_driver(this->Form, REQ_BEG_FIELD);
while (msg[i] != '\0' && i < 60000) {
if (msg[i] == '\n' && msg[i + 1] != '\0') {
form_driver(this->Form, REQ_NEW_LINE);
} else {
form_driver(this->Form, msg[i]);
}
i++;
}
form_driver(this->Form, REQ_BEG_FIELD);
this->UpdateStatusBar();
this->PrintKeys();
touchwin(stdscr);
refresh();
}
void cmCursesLongMessageForm::HandleInput()
{
if (!this->Form) {
return;
}
char debugMessage[128];
for (;;) {
int key = getch();
sprintf(debugMessage, "Message widget handling input, key: %d", key);
cmCursesForm::LogMessage(debugMessage);
// quit
if (key == 'o' || key == 'e') {
break;
}
if (key == KEY_DOWN || key == ctrl('n')) {
form_driver(this->Form, REQ_SCR_FLINE);
} else if (key == KEY_UP || key == ctrl('p')) {
form_driver(this->Form, REQ_SCR_BLINE);
} else if (key == KEY_NPAGE || key == ctrl('d')) {
form_driver(this->Form, REQ_SCR_FPAGE);
} else if (key == KEY_PPAGE || key == ctrl('u')) {
form_driver(this->Form, REQ_SCR_BPAGE);
}
this->UpdateStatusBar();
this->PrintKeys();
touchwin(stdscr);
wrefresh(stdscr);
}
}