Newer
Older
SLC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
SLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SLC; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <ctype.h>
#include <signal.h>
#include <math.h>
/*
*********************************************************************************
*************************************** PUBLIC **********************************
*********************************************************************************
*/
/*!
** Screen constructor
*/
*cmd_buffer_ = 0;
cmd_buf_off_ = 0;
cmd_win_off_ = 0;
cmd_history_off_ = 0;
}
void Screen::init() {
// Init ncurses
initscr();
// register end stop ncurses before exit
atexit((void (*)(void)) endwin);
// Set good parameters
cbreak();
keypad(stdscr, TRUE);
// refresh parameters (needed by ncurses)
/*!
** Create windows clear the screen, destroy already existing windows,
** create windows with good size and draw it.
*/
// Check screen size
if (LINES < 6 || COLS < 3) {
std::cerr << "Screen is too small." << std::endl;
exit(ERR_SCREENSZ);
}
if ((size_t) LINES * 2 > O.history_size)
O.history_size = 2 * LINES;
noecho();
clear();
refresh();
// msg window
if (msg_)
delwin(msg_);
msg_ = newwin(LINES - 3, COLS, 0, 0);
msg_win_buffer_ = (char *) realloc(msg_win_buffer_, COLS -2 + 1);
msg_draw();
// cmd window
if (cmd_)
delwin(cmd_);
cmd_ = newwin(3, COLS, LINES - 3, 0);
cmd_draw();
}
/*!
** Swith into login window mode and
** manage the login/pass ask processus
*/
void Screen::login() {
char *buf;
int size;
const char *smsg;
do {
clear();
box(stdscr, 0,0);
move(1, 1);
// ask login
if (O.login.empty()) {
smsg = "Login: ";
size = COLS - 2 - strlen(smsg);
buf = new char[size + 1];
echo();
printw(smsg);
refresh();
getnstr(buf, size);
buf[size] = 0;
O.login = buf;
delete [] buf;
move(2,1);
}
// ask password
smsg = "Password: ";
size = COLS - 2 - strlen(smsg);
buf = new char[size + 1];
printw(smsg);
refresh();
getnstr(buf, size);
buf[size] = 0;
//nominal screen nom
create_windows();
/*!
** Wait keyboard events and act accordingly
*/
// --------------------------- KEY UP ------------------------------------
memcpy(cmd_history_buffer_, cmd_buffer_, MAX_LINE_SIZE);
strncpy(cmd_buffer_, H.get(cmd_history_off_++).c_str(), MAX_LINE_SIZE);
cmd_buf_off_ = strlen(cmd_buffer_);
// --------------------------- KEY DOWN ----------------------------------
case KEY_DOWN:
if (cmd_history_off_ == 0)
break;
--cmd_history_off_;
if (cmd_history_off_ == 0)
memcpy(cmd_buffer_, cmd_history_buffer_, MAX_LINE_SIZE);
strncpy(cmd_buffer_, H.get(cmd_history_off_ - 1).c_str(), MAX_LINE_SIZE);
cmd_buf_off_ = strlen(cmd_buffer_);
// --------------------------- KEY LEFT ----------------------------------
// --------------------------- KEY RIGHT ---------------------------------
if ((size_t) cmd_buf_off_ < strlen(cmd_buffer_))
++cmd_buf_off_;
// --------------------------- KEY HOME ----------------------------------
// --------------------------- KEY END -----------------------------------
case KEY_END:
cmd_buf_off_ = strlen(cmd_buffer_);
// --------------------------- KEY RETURN --------------------------------
// check non empty buffer
if (*cmd_buffer_ == 0) break;
if (strncmp(cmd_buffer_, "/pass", 4))
H.add(cmd_buffer_);
// print result
cmd_draw();
// --------------------------- KEY BACKSPACE------------------------------
if (del_char(cmd_buffer_, cmd_buf_off_ - 1, MAX_LINE_SIZE))
--cmd_buf_off_;
cmd_draw();
// --------------------------- KEY DELETE --------------------------------
del_char(cmd_buffer_, cmd_buf_off_, MAX_LINE_SIZE);
// --------------------------- KEY RESIZE --------------------------------
case KEY_RESIZE:
create_windows();
// --------------------------- KEY EOF -----------------------------------
// -------------------------ALL OTHERS KEYS ------------------------------
if (add_char(key, cmd_buffer_, cmd_buf_off_, MAX_LINE_SIZE))
** Print a message in msg window (on one line)
void Screen::msg_println(const string &s) {
msg_buffer_ << s;
msg_print("\n");
}
/*!
** Print a number in msg window (on one line)
**
** @param s message to print
*/
void Screen::msg_println(int i) {
msg_buffer_ << i;
msg_print("\n");
}
/*!
** Print @param s into msg window (no refresh)
*/
size_t offset = 0;
size_t last = 0;
msg_buffer_ << s;
const string &buf = msg_buffer_.str();
// add line by line
while ((offset = buf.find('\n', last)) != string::npos) {
msg_add(buf.substr(last, offset - last));
last = offset + 1;
}
// update screen
if (last > 0) {
msg_buffer_.str("");
msg_draw();
cmd_draw();
}
/*!
** Print @param i into msg window (no refresh)
*/
void Screen::msg_print(int i) {
msg_buffer_ << i;
}
/*
*********************************************************************************
************************************** PRIVATE **********************************
*********************************************************************************
*/
/*!
** Draw the content of the cmd window
*/
// clean and redraw the cmd box
werase(cmd_);
box(cmd_, 0, 0);
wmove(cmd_, 1, 1);
if (cmd_buf_off_ + 1 > (size_t) COLS - 2 + cmd_win_off_)
cmd_win_off_ = cmd_buf_off_ + 1 - (COLS - 2) ;
else if (cmd_buf_off_ < cmd_win_off_)
cmd_win_off_ = cmd_buf_off_;
size_t minsize = (MAX_LINE_SIZE < COLS - 2) ? MAX_LINE_SIZE : COLS - 2;
strncpy(print_buf, cmd_buffer_ + cmd_win_off_, minsize);
// print print buffer
wattron(cmd_, A_BOLD);
wprintw(cmd_, "%s", print_buf);
wattroff(cmd_, A_BOLD);
// move cursor to right pos
wmove(cmd_, 1, 1 + cmd_buf_off_ - cmd_win_off_);
/*!
** Draw the content of the msg window
*/
void Screen::msg_draw() {
werase(msg_);
box(msg_, 0, 0);
t_lines::const_iterator line;
size_t free_lines = LINES - 5;
for (line = msg_table_.begin(); line != msg_table_.end() && free_lines > 0; ++line) {
size_t len = strlen((*line).c_str());
// print one line
if (len <= (size_t) COLS - 2)
mvwprintw(msg_, free_lines--, 1, "%s", (*line).c_str());
// print multi line
else {
// compute line count
const size_t nline = 1 + (size_t) ceil(((double) ( len - (COLS - 2)) / (double) (COLS - 4)));
// iterate for each line starting with the last
for (size_t i = nline; i > 0 && free_lines > 0; --i) {
// compute string offset for this line
const size_t print_offset = (i == 1) ? 0 : COLS - 2 + ((i - 2) * (COLS - 4));
// copy line into a buffer
strncpy(msg_win_buffer_, (*line).c_str() + print_offset, COLS - ((i == 1) ? 2 : 4));
msg_win_buffer_[COLS - ((i == 1) ? 2 : 4)] = 0;
mvwprintw(msg_, free_lines--, 1, (i == 1) ? "%s" : "| %s", msg_win_buffer_);
** Add char @param c in a @param string buffer at offset @param offset.
** @param buf_len is the size of the buffer
*/
bool Screen::add_char(char c, char *string, ssize_t offset, size_t buf_len) {
// check if add one char is in range
if (len + 1 > buf_len - 1)
return false;
// check if offset is good
if (offset >= (ssize_t) buf_len - 1 || offset < 0)
// move one char every char
for (ssize_t i = len; i >= offset; --i)
string[i + 1] = string[i];
string[offset] = c;
/*!
** Del a char from @param string at offset @param offset.
** @param buf_len is the buffer size
**
** @return
*/
bool Screen::del_char(char *string, ssize_t offset, size_t buf_len) {
assert(string);
size_t len = strlen(string);
// check if del one char is possible
if (len == 0)
// check if offset is good
if (offset >= (ssize_t) buf_len - 1 || offset < 0)
// move one char every char
for (; string[offset] != 0; ++offset)
string[offset] = string[offset + 1];
assert(s.find('\n') == string::npos);
if (msg_table_.size() >= O.history_size)
msg_table_.resize(O.history_size);
msg_table_.push_front(s);
/*!
** Retrieve @param i th msg from msg list
** @return string corresponding to @param i in msg list
*/
const string &Screen::msg_get(size_t i) const {
assert(i < msg_table_.size());
t_lines::const_iterator it;
size_t pos;
static string empty;
for (pos = 0, it = msg_table_.begin();
it != msg_table_.end();
++pos, ++it)
if (pos == i)
return *it;
return empty;
/*!
** Compute the size of msg list
**
** @return count of message in msg list
*/
size_t Screen::msg_size() const {
return msg_table_.size();
}
/*!
** Load msg list from a file @param filename
*/
void Screen::msg_load(const string &filename) {
ifstream fs;
t_lines::const_iterator it;
char buf[MAX_LINE_SIZE];
fs.open(filename.c_str(), ifstream::in);
if (!fs.is_open())
return;
while (!fs.eof()) {
if (fs.fail())
throw Error(ERR_FILE, "Unable to load history");
fs.getline(buf, MAX_LINE_SIZE);
msg_add(buf);
}
fs.close();
}
/*!
** Save msg list to a file @param filename
*/
void Screen::msg_save(const string &filename) const {
ofstream fs;
t_lines::const_reverse_iterator rit;
fs.open(filename.c_str(), ostream::out | ostream::trunc);
if (!fs.is_open())
throw Error(ERR_FILE, "Unable to open history file");
for (rit = msg_table_.rbegin(); rit != msg_table_.rend(); ++rit) {
fs.write((*rit).c_str(), (*rit).length());
fs.put('\n');
if (fs.fail())
throw Error(ERR_FILE, "Unable to save history");
}
fs.close();
/*!
** This is a sugar to print msg on msg window
**
** @param scr A Screen
** @param s string to print
**
** @return @param scr
*/
Screen &operator<< (Screen &scr, const string &s) {
scr.msg_print(s);
/*!
** This is a sugar to print msg on msg window
**
** @param scr A Screen
** @param i string to print
**
** @return @param scr
*/
Screen &operator<< (Screen &scr, int i) {
scr.msg_print(i);
return scr;
}