diff --git a/.gitignore b/.gitignore index 65cc6f2e..b8aa0e2a 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ examples/.deps/ examples/.libs/ examples/calculator examples/dialog +examples/event-log examples/string-operations examples/background-color examples/opti-move diff --git a/.travis.yml b/.travis.yml index f7b5d2a0..dfeb55a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,12 +75,12 @@ matrix: - whoami - echo -n | openssl s_client -CApath /etc/ssl/certs/ -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-certificates.crt script: - - cat /home/travis/build/gansm/finalcut/cov-int/scm_log.txt + - cat /home/travis/build/gansm/finalcut/cov-int/scm_log.txt || echo - autoreconf -v --install --force - ./configure --prefix=/usr CPPFLAGS="-DDEBUG" CXXFLAGS="-g -O0 -DDEBUG -DUNIT_TEST" --with-unit-test - make V=1 -j10 - make check - - cat test/*.log + - cat test/*.log || echo # # Coveralls + Codecov diff --git a/ChangeLog b/ChangeLog index 8d9b16e8..0cd37691 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-05-13 Markus Gans + * The new class FLogger for logging, which can be redirected + to different I/O channels + * Adding the event-log example to show the logging functionality + 2020-05-02 Markus Gans * Transfer of all termcap functions into the FTermcap class diff --git a/examples/Makefile.am b/examples/Makefile.am index 8de96be7..9514ec2b 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -11,6 +11,7 @@ noinst_PROGRAMS = \ hello \ dialog \ input-dialog \ + event-log \ fullwidth-character \ 7segment \ choice \ @@ -39,6 +40,7 @@ noinst_PROGRAMS = \ hello_SOURCES = hello.cpp dialog_SOURCES = dialog.cpp input_dialog_SOURCES = input-dialog.cpp +event_log_SOURCES = event-log.cpp fullwidth_character_SOURCES = fullwidth-character.cpp 7segment_SOURCES = 7segment.cpp choice_SOURCES = choice.cpp diff --git a/examples/background-color.cpp b/examples/background-color.cpp index 8cf6f0bd..4960a658 100644 --- a/examples/background-color.cpp +++ b/examples/background-color.cpp @@ -211,7 +211,6 @@ void Background::cb_choice (const finalcut::FWidget*, const FDataPtr) updateTerminal(); } - //---------------------------------------------------------------------- // main part //---------------------------------------------------------------------- @@ -226,6 +225,20 @@ int main (int argc, char* argv[]) Background dialog(&app); finalcut::FWidget::setMainWidget(&dialog); dialog.show(); +//------------------------------------------------- + std::cout << "\r\n" << std::flush; + finalcut::FLog& log = *finalcut::FApplication::getLog(); + + //std::ofstream file_stream("test.log", std::ofstream::out | std::ofstream::app); + //log.setLineEnding (finalcut::FLog::LF); + //log.setOutputStream(file_stream); + + log.info("test1"); + log.warn("test2"); + log << finalcut::FLog::Error << "streaming " << "test 1" << std::flush; + log.enableTimestamp(); + log << finalcut::FLog::Debug << "streaming test 2"; +//------------------------------------------------- return app.exec(); } diff --git a/examples/event-log.cpp b/examples/event-log.cpp new file mode 100644 index 00000000..1d17561e --- /dev/null +++ b/examples/event-log.cpp @@ -0,0 +1,353 @@ +/*********************************************************************** +* event-log.cpp - Logs events in a dialog box * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2020 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public License * +* as published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* The Final Cut 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 Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +#include +#include +#include +#include +#include + +#include + +using finalcut::FPoint; +using finalcut::FRect; +using finalcut::FSize; + +class EventLog; // class forward declaration + +//---------------------------------------------------------------------- +// class EventLog::EventLog +//---------------------------------------------------------------------- + +class EventDialog final : public finalcut::FDialog +{ + public: + // Using-declaration + using FDialog::setGeometry; + + // Constructor + explicit EventDialog (finalcut::FWidget* = nullptr); + + // Disable copy constructor + EventDialog (const EventDialog&) = delete; + + // Destructor + ~EventDialog(); + + // Disable copy assignment operator (=) + EventDialog& operator = (const EventDialog&) = delete; + + private: + // Methods + finalcut::FString getMouseButtonName (int); + void logMouseEvent (finalcut::FString, finalcut::FMouseEvent&); + + // Event handlers + void onClose (finalcut::FCloseEvent*) override; + void onShow (finalcut::FShowEvent*) override; + void onTimer (finalcut::FTimerEvent*) override; + void onKeyPress (finalcut::FKeyEvent*) override; + void onMouseDown (finalcut::FMouseEvent*) override; + void onMouseMove (finalcut::FMouseEvent*) override; + void onMouseUp (finalcut::FMouseEvent*) override; + void onMouseDoubleClick (finalcut::FMouseEvent* ev) override; + void onWindowActive (finalcut::FEvent*) override; + void onWindowInactive (finalcut::FEvent*) override; + void onWindowRaised (finalcut::FEvent*) override; + void onWindowLowered (finalcut::FEvent*) override; + + private: + // Data members + finalcut::FLog& log{*finalcut::FApplication::getLog()}; + finalcut::FLabel label{this}; +}; + +//---------------------------------------------------------------------- +EventDialog::EventDialog (finalcut::FWidget* parent) + : FDialog(parent) +{ + // Dialog settings + // Avoids calling a virtual function from the constructor + // (CERT, OOP50-CPP) + FDialog::setText ("Event dialog"); + FDialog::setGeometry (FPoint{15, 2}, FSize{53, 12}); + setShadow(); + label.setText("\n\nUse the keyboard or mouse\n" + "in this dialog to create events"); + label.setAlignment(finalcut::fc::alignCenter); + label.setGeometry (FPoint(1, 1), getClientSize(), false); + addTimer(60000); // Starts the timer every minute +} + +//---------------------------------------------------------------------- +EventDialog::~EventDialog() // destructor +{ } + +//---------------------------------------------------------------------- +finalcut::FString EventDialog::getMouseButtonName (int btn_state) +{ + switch ( btn_state ) + { + case finalcut::fc::LeftButton: + return "left"; + + case finalcut::fc::RightButton: + return "right"; + + case finalcut::fc::MiddleButton: + return "middle"; + + default: + return "unknown"; + } + + return "unknown"; +} + +//---------------------------------------------------------------------- +void EventDialog::logMouseEvent ( finalcut::FString state + , finalcut::FMouseEvent& ev ) +{ + const int mouse_x = ev.getX(); + const int mouse_y = ev.getY(); + + log << finalcut::FLog::Info + << getMouseButtonName(ev.getButton()) + << " mouse button " << state << " at (" + << mouse_x << ", " << mouse_y << ")" << std::flush; +} + +//---------------------------------------------------------------------- +void EventDialog::onClose (finalcut::FCloseEvent* ev) +{ + log.info("The event dialog was closed"); + ev->accept(); +} + +//---------------------------------------------------------------------- +void EventDialog::onShow (finalcut::FShowEvent*) +{ + log.info("The event dialog is now displayed"); +} + +//---------------------------------------------------------------------- +void EventDialog::onTimer (finalcut::FTimerEvent*) +{ + log.info("-- minute marker --"); +} + + +//---------------------------------------------------------------------- +void EventDialog::onKeyPress (finalcut::FKeyEvent* ev) +{ + const FKey key_id = ev->key(); + finalcut::FString key_name = getKeyName(key_id); + + if ( key_name.isEmpty() ) + key_name = wchar_t(key_id); + + log << finalcut::FLog::Info + << "Key " << key_name << " (id " << key_id << ")" << std::flush; + + finalcut::FDialog::onKeyPress(ev); +} + +//---------------------------------------------------------------------- +void EventDialog::onMouseDown (finalcut::FMouseEvent* ev) +{ + logMouseEvent("down", *ev); + finalcut::FDialog::onMouseDown(ev); +} + +//---------------------------------------------------------------------- +void EventDialog::onMouseMove (finalcut::FMouseEvent* ev) +{ + logMouseEvent("move", *ev); + finalcut::FDialog::onMouseMove(ev); +} + +//---------------------------------------------------------------------- +void EventDialog::onMouseUp (finalcut::FMouseEvent* ev) +{ + logMouseEvent("up", *ev); + finalcut::FDialog::onMouseUp(ev); +} + +//---------------------------------------------------------------------- +void EventDialog::onMouseDoubleClick (finalcut::FMouseEvent* ev) +{ + logMouseEvent("double click", *ev); + finalcut::FDialog::onMouseDoubleClick(ev); +} + +//---------------------------------------------------------------------- +void EventDialog::onWindowActive (finalcut::FEvent* ev) +{ + log.info("The Event dialog is now active"); + finalcut::FDialog::onWindowActive(ev); +} + +//---------------------------------------------------------------------- +void EventDialog::onWindowInactive (finalcut::FEvent* ev) +{ + log.info("The Event dialog is now inactive"); + finalcut::FDialog::onWindowInactive(ev); +} + + +//---------------------------------------------------------------------- +void EventDialog::onWindowRaised (finalcut::FEvent* ev) +{ + log.info("The dialog was raised"); + finalcut::FDialog::onWindowRaised(ev); +} + +//---------------------------------------------------------------------- +void EventDialog::onWindowLowered (finalcut::FEvent* ev) +{ + log.info("The dialog was lowered"); + finalcut::FDialog::onWindowLowered(ev); +} + + +//---------------------------------------------------------------------- +// class EventLog +//---------------------------------------------------------------------- + +class EventLog final : public finalcut::FDialog, public std::ostringstream +{ + public: + // Using-declaration + using FDialog::setGeometry; + + // Constructor + explicit EventLog (finalcut::FWidget* = nullptr); + + // Disable copy constructor + EventLog (const EventLog&) = delete; + + // Destructor + ~EventLog(); + + // Disable copy assignment operator (=) + EventLog& operator = (const EventLog&) = delete; + + // Event handlers + void onTimer (finalcut::FTimerEvent*) override; + void onClose (finalcut::FCloseEvent*) override; + + private: + // Method + void adjustSize() override; + + // Data members + finalcut::FTextView scrollText{this}; + EventDialog* event_dialog{new EventDialog(this)}; +}; + +//---------------------------------------------------------------------- +EventLog::EventLog (finalcut::FWidget* parent) + : FDialog(parent) +{ + // Dialog settings + // Avoids calling a virtual function from the constructor + // (CERT, OOP50-CPP) + FDialog::setText ("Event log"); + FDialog::setGeometry (FPoint{4, 16}, FSize{75, 8}); + setMinimumSize (FSize{75, 5}); + setResizeable(); + setShadow(); + scrollText.ignorePadding(); + scrollText.setGeometry (FPoint{1, 2}, FSize{getWidth(), getHeight() - 1}); + event_dialog->setFocus(); + addTimer(250); // Starts the timer every 250 milliseconds +} + +//---------------------------------------------------------------------- +EventLog::~EventLog() // destructor +{ } + +//---------------------------------------------------------------------- +void EventLog::onTimer (finalcut::FTimerEvent*) +{ + if ( ! str().empty() ) + { + scrollText.append(str()); + str(""); + scrollText.scrollToEnd(); + redraw(); + updateTerminal(); + } +} + +//---------------------------------------------------------------------- +void EventLog::onClose (finalcut::FCloseEvent* ev) +{ + finalcut::FApplication::closeConfirmationDialog (this, ev); +} + +//---------------------------------------------------------------------- +void EventLog::adjustSize() +{ + finalcut::FDialog::adjustSize(); + scrollText.setGeometry (FPoint{1, 2}, FSize(getWidth(), getHeight() - 1)); +} + + +//---------------------------------------------------------------------- +// main part +//---------------------------------------------------------------------- + +int main (int argc, char* argv[]) +{ + finalcut::FApplication app(argc, argv); + EventLog dialog(&app); + + // Get the global logger object + finalcut::FLog& log = *finalcut::FApplication::getLog(); + + // Set the line endings (default = CRLF) + log.setLineEnding (finalcut::FLog::LF); + + // Write a timestamp before each output line + log.enableTimestamp(); + + // Set the dialog object as output stream + log.setOutputStream(dialog); + + // ---------------------------------------------- + // Remove the comment characters in the following + // two lines to log the output to a file. + // ---------------------------------------------- + //std::ofstream file_stream("test.log", std::ofstream::out | std::ofstream::app); + //log.setOutputStream(file_stream); + + // Sets the dialog as main widget + finalcut::FWidget::setMainWidget(&dialog); + + // Show the dialog + dialog.show(); + + // Run the application + return app.exec(); +} + diff --git a/examples/string-operations.cpp b/examples/string-operations.cpp index 2ef0b14f..8dcd7a16 100644 --- a/examples/string-operations.cpp +++ b/examples/string-operations.cpp @@ -226,15 +226,15 @@ void streamToInterger() } catch (const std::underflow_error& ex) { - std::cerr << "underflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Underflow"); } catch (const std::overflow_error& ex) { - std::cerr << "overflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Overflow"); } catch (const std::invalid_argument& ex) { - std::cerr << "Arithmetic error: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Arithmetic error"); } } @@ -250,15 +250,15 @@ void streamToUnsignedInterger() } catch (const std::underflow_error& ex) { - std::cerr << "underflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Underflow"); } catch (const std::overflow_error& ex) { - std::cerr << "overflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Overflow"); } catch (const std::invalid_argument& ex) { - std::cerr << "Arithmetic error: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Arithmetic error"); } } @@ -274,15 +274,15 @@ void streamToDouble() } catch (const std::underflow_error& ex) { - std::cerr << "underflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Underflow"); } catch (const std::overflow_error& ex) { - std::cerr << "overflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Overflow"); } catch (const std::invalid_argument& ex) { - std::cerr << "Arithmetic error: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Arithmetic error"); } } @@ -298,15 +298,15 @@ void streamToFloat() } catch (const std::underflow_error& ex) { - std::cerr << "underflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Underflow"); } catch (const std::overflow_error& ex) { - std::cerr << "overflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Overflow"); } catch (const std::invalid_argument& ex) { - std::cerr << "Arithmetic error: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Arithmetic error"); } } @@ -498,15 +498,15 @@ void convertToNumberExample() } catch (const std::underflow_error& ex) { - std::cerr << "underflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Underflow"); } catch (const std::overflow_error& ex) { - std::cerr << "overflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Overflow"); } catch (const std::invalid_argument& ex) { - std::cerr << "Arithmetic error: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Arithmetic error"); } // Test: convert a string to a signed long interger @@ -517,15 +517,15 @@ void convertToNumberExample() } catch (const std::underflow_error& ex) { - std::cerr << "underflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Underflow"); } catch (const std::overflow_error& ex) { - std::cerr << "overflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Overflow"); } catch (const std::invalid_argument& ex) { - std::cerr << "Arithmetic error: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Arithmetic error"); } // Test: convert a string to a double value @@ -542,15 +542,15 @@ void convertToNumberExample() } catch (const std::underflow_error& ex) { - std::cerr << "underflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Underflow"); } catch (const std::overflow_error& ex) { - std::cerr << "overflow: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Overflow"); } catch (const std::invalid_argument& ex) { - std::cerr << "Arithmetic error: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Arithmetic error"); } } @@ -640,9 +640,9 @@ void insertExample() std::cout << " insert: " << insert_str.insert("changed ", 7) << std::endl; } - catch (const std::out_of_range& ex) + catch (const std::out_of_range&) { - std::cerr << "Out of Range error: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Out of Range"); } } @@ -655,14 +655,14 @@ void indexExample() try { - index[0] = L'I'; // write a wide character at position 0 + index[0] = L'I'; // Write a wide character at position 0 printf ( " index: [0] = %c ; [4] = %c\n" , char(index[0]) , char(index[4]) ); } catch (const std::out_of_range& ex) { - std::cerr << "Out of Range error: " << ex.what() << std::endl; + finalcut::FApplication::getLog()->error("Out of Range"); } } diff --git a/examples/ui.cpp b/examples/ui.cpp index 4565e4f0..07002b8e 100644 --- a/examples/ui.cpp +++ b/examples/ui.cpp @@ -981,7 +981,7 @@ void MyDialog::cb_view (const finalcut::FWidget*, FDataPtr data) int(getRootWidget()->getHeight() / 6) } , FSize{60, getRootWidget()->getHeight() * 3 / 4} ); view->setResizeable(); - std::string line = ""; + std::string line{""}; std::ifstream infile; infile.open(file); @@ -1028,7 +1028,7 @@ int main (int argc, char* argv[]) //app.setEncoding(finalcut::fc::VT100); // Sets the terminal size to 94×30 - //app.setTermSize(94,30); + //finalcut::FTerm::setTermSize(FSize{94, 30}); // Enable the final cut graphical font //app.setNewFont(); diff --git a/src/Makefile.am b/src/Makefile.am index 846b28be..80c74b67 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,8 @@ libfinal_la_SOURCES = \ flabel.cpp \ flistbox.cpp \ flistview.cpp \ + flog.cpp \ + flogger.cpp \ fmenu.cpp \ fmouse.cpp \ fsystem.cpp \ @@ -98,6 +100,8 @@ finalcutinclude_HEADERS = \ include/final/flineedit.h \ include/final/flistbox.h \ include/final/flistview.h \ + include/final/flog.h \ + include/final/flogger.h \ include/final/fmenu.h \ include/final/fmouse.h \ include/final/fkeyboard.h \ diff --git a/src/Makefile.clang b/src/Makefile.clang index 0429f70d..55691c9c 100644 --- a/src/Makefile.clang +++ b/src/Makefile.clang @@ -25,6 +25,8 @@ INCLUDE_HEADERS = \ flineedit.h \ flistbox.h \ flistview.h \ + flog.h \ + flogger.h \ fmenu.h \ fdialoglistmenu.h \ fmenubar.h \ @@ -98,6 +100,8 @@ OBJS = \ flabel.o \ flistbox.o \ flistview.o \ + flog.o \ + flogger.o \ fmenu.o \ fdialoglistmenu.o \ fmenubar.o \ diff --git a/src/Makefile.gcc b/src/Makefile.gcc index d3c5c420..d1d2f3a2 100644 --- a/src/Makefile.gcc +++ b/src/Makefile.gcc @@ -25,6 +25,8 @@ INCLUDE_HEADERS = \ flineedit.h \ flistbox.h \ flistview.h \ + flog.h \ + flogger.h \ fmenu.h \ fdialoglistmenu.h \ fmenubar.h \ @@ -98,6 +100,8 @@ OBJS = \ flabel.o \ flistbox.o \ flistview.o \ + flog.o \ + flogger.o \ fmenu.o \ fdialoglistmenu.o \ fmenubar.o \ diff --git a/src/fapplication.cpp b/src/fapplication.cpp index 8d8b6294..b35cf55c 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -25,6 +25,8 @@ #include "final/fapplication.h" #include "final/fevent.h" +#include "final/flog.h" +#include "final/flogger.h" #include "final/fmenu.h" #include "final/fmenubar.h" #include "final/fmessagebox.h" @@ -108,6 +110,20 @@ FApplication* FApplication::getApplicationObject() return app_object; } +//---------------------------------------------------------------------- +std::shared_ptr& FApplication::getLog() +{ + // Global logger object + static std::shared_ptr logger = std::make_shared(); + return logger; +} + +//---------------------------------------------------------------------- +void FApplication::setLog (const std::shared_ptr& logger) +{ + getLog() = logger; +} + //---------------------------------------------------------------------- bool FApplication::isQuit() { @@ -349,6 +365,9 @@ void FApplication::init (uInt64 key_time, uInt64 dblclick_time) // Set the default double click interval if ( mouse ) mouse->setDblclickInterval (dblclick_time); + + // Initialize logging + getLog()->setLineEnding(FLog::CRLF); } //---------------------------------------------------------------------- @@ -1094,6 +1113,17 @@ void FApplication::processCloseWidget() setTerminalUpdates (FVTerm::start_terminal_updates); } +//---------------------------------------------------------------------- +void FApplication::processLogger() +{ + // Synchronizing the stream buffer with the logging output + + auto logger = getLog(); + + if ( ! logger->str().empty() ) + logger->pubsync(); +} + //---------------------------------------------------------------------- bool FApplication::processNextEvent() { @@ -1104,6 +1134,7 @@ bool FApplication::processNextEvent() processResizeEvent(); processTerminalUpdate(); processCloseWidget(); + processLogger(); sendQueuedEvents(); num_events += processTimerEvent(); diff --git a/src/fcombobox.cpp b/src/fcombobox.cpp index c4f3930a..3969c622 100644 --- a/src/fcombobox.cpp +++ b/src/fcombobox.cpp @@ -27,6 +27,7 @@ #include "final/flabel.h" #include "final/flineedit.h" #include "final/flistbox.h" +#include "final/flog.h" #include "final/fmouse.h" #include "final/fpoint.h" #include "final/fsize.h" @@ -605,9 +606,9 @@ void FComboBox::passEventToListWindow (FMouseEvent* const& ev) list_window.list.setFocus(); list_window.list.onMouseMove(_ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); } } @@ -631,6 +632,7 @@ void FComboBox::cb_setInputField (const FWidget*, const FDataPtr) input_field = list.getItem(index).getText(); input_field.redraw(); processChanged(); + std::cout << "\r\n"; } //---------------------------------------------------------------------- @@ -692,9 +694,9 @@ void FComboBox::cb_inputFieldHandOver (const FWidget*, const FDataPtr) list_window.list.setFocus(); list_window.list.onMouseMove(_ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); } } diff --git a/src/fdialog.cpp b/src/fdialog.cpp index 8ea0335e..0aa073a3 100644 --- a/src/fdialog.cpp +++ b/src/fdialog.cpp @@ -824,9 +824,9 @@ void FDialog::initDialogMenu() { dialog_menu = new FMenu ("-", this); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMenu"); return; } @@ -854,9 +854,9 @@ void FDialog::initMoveSizeMenuItem (FMenu* menu) { move_size_item = new FMenuItem (menu); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMenuItem"); return; } @@ -877,9 +877,9 @@ void FDialog::initZoomMenuItem (FMenu* menu) { zoom_item = new FMenuItem (menu); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMenuItem"); return; } @@ -900,9 +900,9 @@ void FDialog::initCloseMenuItem (FMenu* menu) { close_item = new FMenuItem ("&Close", menu); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMenuItem"); return; } @@ -1358,9 +1358,9 @@ inline void FDialog::passEventToSubMenu ( const mouseStates& ms setClickedWidget(dialog_menu); dialog_menu->onMouseMove(_ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); return; } } @@ -1646,9 +1646,9 @@ void FDialog::cb_move (const FWidget*, const FDataPtr) { tooltip = new FToolTip(this); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FToolTip"); return; } diff --git a/src/flabel.cpp b/src/flabel.cpp index a527fb57..d47feadc 100644 --- a/src/flabel.cpp +++ b/src/flabel.cpp @@ -27,6 +27,7 @@ #include "final/fcolorpair.h" #include "final/fevent.h" #include "final/flabel.h" +#include "final/flog.h" #include "final/fstatusbar.h" namespace finalcut @@ -173,9 +174,9 @@ void FLabel::onMouseDown (FMouseEvent* ev) std::make_shared(fc::MouseDown_Event, p, tp, b); FApplication::sendEvent (parent, _ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); return; } } diff --git a/src/flineedit.cpp b/src/flineedit.cpp index 6a4bf64a..639c9881 100644 --- a/src/flineedit.cpp +++ b/src/flineedit.cpp @@ -25,6 +25,7 @@ #include "final/fapplication.h" #include "final/fevent.h" #include "final/flabel.h" +#include "final/flog.h" #include "final/flineedit.h" #include "final/fpoint.h" #include "final/fsize.h" @@ -860,7 +861,8 @@ inline FLineEdit::offsetPair FLineEdit::endPosToOffset (std::size_t pos) } catch (const std::out_of_range& ex) { - std::cerr << "Out of Range error: " << ex.what() << std::endl; + *FApplication::getLog() << FLog::Error + << "Out of Range error: " << ex.what() << std::endl; } if ( input_width >= char_width ) @@ -883,7 +885,8 @@ inline FLineEdit::offsetPair FLineEdit::endPosToOffset (std::size_t pos) } catch (const std::out_of_range& ex) { - std::cerr << "Out of Range error: " << ex.what() << std::endl; + *FApplication::getLog() << FLog::Error + << "Out of Range error: " << ex.what() << std::endl; } } @@ -918,7 +921,8 @@ std::size_t FLineEdit::clickPosToCursorPos (std::size_t pos) } catch (const std::out_of_range& ex) { - std::cerr << "Out of Range error: " << ex.what() << std::endl; + *FApplication::getLog() << FLog::Error + << "Out of Range error: " << ex.what() << std::endl; } idx++; @@ -951,7 +955,8 @@ void FLineEdit::adjustTextOffset() } catch (const std::out_of_range& ex) { - std::cerr << "Out of Range error: " << ex.what() << std::endl; + *FApplication::getLog() << FLog::Error + << "Out of Range error: " << ex.what() << std::endl; } } @@ -963,7 +968,8 @@ void FLineEdit::adjustTextOffset() } catch (const std::out_of_range& ex) { - std::cerr << "Out of Range error: " << ex.what() << std::endl; + *FApplication::getLog() << FLog::Error + << "Out of Range error: " << ex.what() << std::endl; } } diff --git a/src/flistview.cpp b/src/flistview.cpp index 9d769553..5fd2361c 100644 --- a/src/flistview.cpp +++ b/src/flistview.cpp @@ -910,9 +910,9 @@ FObject::iterator FListView::insert ( const FStringList& cols { item = new FListViewItem (cols, d, getNullIterator()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FListViewItem"); return getNullIterator(); } diff --git a/src/flog.cpp b/src/flog.cpp new file mode 100644 index 00000000..f2b991b0 --- /dev/null +++ b/src/flog.cpp @@ -0,0 +1,87 @@ +/*********************************************************************** +* flog.cpp - Interface of the FINAL CUT logger * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2020 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public License * +* as published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* The Final Cut 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 Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +#include "final/flog.h" + +namespace finalcut +{ + +//---------------------------------------------------------------------- +// class FLog +//---------------------------------------------------------------------- + +// constructors and destructor +//---------------------------------------------------------------------- +FLog::FLog() +{ } + +//---------------------------------------------------------------------- +FLog::~FLog() // destructor +{ + sync(); +} + + +// public methods of FLog +//---------------------------------------------------------------------- +FLog& FLog::operator << (LogLevel l) +{ + sync(); + + switch ( l ) + { + case Info: + current_log = std::bind(&FLog::info, this, _1); + break; + + case Warn: + current_log = std::bind(&FLog::warn, this, _1); + break; + + case Error: + current_log = std::bind(&FLog::error, this, _1); + break; + + case Debug: + current_log = std::bind(&FLog::debug, this, _1); + break; + } + + return *this; +} + + +// protected methods of FLog +//---------------------------------------------------------------------- +int FLog::sync() +{ + if ( ! str().empty() ) + { + current_log (str()); + str(""); + } + + return 0; +} + +} // namespace finalcut + diff --git a/src/flogger.cpp b/src/flogger.cpp new file mode 100644 index 00000000..04c34baa --- /dev/null +++ b/src/flogger.cpp @@ -0,0 +1,124 @@ +/*********************************************************************** +* flogger.cpp - The FINAL CUT text logger * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2020 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public License * +* as published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* The Final Cut 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 Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +#include "final/flogger.h" + +namespace finalcut +{ + +//---------------------------------------------------------------------- +// class FLogger +//---------------------------------------------------------------------- + +// constructors and destructor +//---------------------------------------------------------------------- +FLogger::FLogger() +{ } + +//---------------------------------------------------------------------- +FLogger::~FLogger() // destructor +{ } + + +// private methods of FLogger +//---------------------------------------------------------------------- +void FLogger::newlineReplace ( std::string& str + , const std::string& replace_str ) +{ + std::size_t pos{0}; + std::size_t npos{std::string::npos}; + + while ( (pos = str.find("\n", pos)) != npos + && pos + 1 < str.length() ) + { + str.replace(pos, 1, replace_str); + pos += replace_str.length(); + } +} + +//---------------------------------------------------------------------- +const std::string FLogger::getTimeString() +{ + char str[100]; + const auto& now = std::chrono::system_clock::now(); + const auto& t = std::chrono::system_clock::to_time_t(now); + std::stringstream str_stream; + // Print RFC 2822 date + const auto& tm = std::localtime(&t); + std::strftime(str, sizeof(str), "%a, %d %b %Y %T %z", tm); + return std::string(str); +} + +//---------------------------------------------------------------------- +const std::string FLogger::getEOL() +{ + if ( end_of_line == FLog::LF ) + return "\n"; + else if ( end_of_line == FLog::CR ) + return "\r"; + else if ( end_of_line == FLog::CRLF ) + return "\r\n"; + + return ""; +} + +//---------------------------------------------------------------------- +void FLogger::printLogLine (const std::string& msg) +{ + const std::string& log_level = [this] () + { + switch ( level ) + { + case Info: + return "INFO"; + + case Warn: + return "WARNING"; + + case Error: + return "ERROR"; + + case Debug: + return "DEBUG"; + } + + return ""; + }(); + + const std::string prefix = [this, &log_level] () + { + if ( timestamp ) + return getTimeString() + " [" + log_level + "] "; + else + return "[" + log_level + "] "; + }(); + + std::string message{msg}; + const std::string& eol = getEOL(); + const std::string replace_str = eol + prefix; + newlineReplace (message, replace_str); + output << prefix << message << eol; +} + +} // namespace finalcut + + diff --git a/src/fmenu.cpp b/src/fmenu.cpp index c6b24c01..c8eed290 100644 --- a/src/fmenu.cpp +++ b/src/fmenu.cpp @@ -28,6 +28,7 @@ #include "final/fcolorpair.h" #include "final/fdialog.h" #include "final/fevent.h" +#include "final/flog.h" #include "final/fmenu.h" #include "final/fmenubar.h" #include "final/fmenuitem.h" @@ -941,9 +942,9 @@ void FMenu::passEventToSubMenu (FMouseEvent* const& ev) setClickedWidget(opened_sub_menu); opened_sub_menu->onMouseMove(_ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); } } @@ -965,9 +966,9 @@ void FMenu::passEventToSuperMenu (FMouseEvent* const& ev) setClickedWidget(smenu); smenu->onMouseMove(_ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); } } @@ -990,9 +991,9 @@ void FMenu::passEventToMenuBar (FMouseEvent* const& ev) mbar.mouse_down = true; mbar.onMouseMove(_ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); } } diff --git a/src/fmenubar.cpp b/src/fmenubar.cpp index 02fa0ce4..bf50c10e 100644 --- a/src/fmenubar.cpp +++ b/src/fmenubar.cpp @@ -25,6 +25,7 @@ #include "final/fapplication.h" #include "final/fevent.h" +#include "final/flog.h" #include "final/fmenu.h" #include "final/fmenubar.h" #include "final/fmenuitem.h" @@ -944,9 +945,9 @@ void FMenuBar::passEventToMenu (const FMouseEvent* const& ev) setClickedWidget(menu); menu->onMouseMove(_ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); } } } diff --git a/src/fmenuitem.cpp b/src/fmenuitem.cpp index fbd174b5..e6013171 100644 --- a/src/fmenuitem.cpp +++ b/src/fmenuitem.cpp @@ -25,6 +25,7 @@ #include "final/fapplication.h" #include "final/fdialog.h" #include "final/fevent.h" +#include "final/flog.h" #include "final/fmenu.h" #include "final/fmenubar.h" #include "final/fmenulist.h" @@ -614,9 +615,9 @@ void FMenuItem::createDialogList (FMenu* winmenu) // create a new dialog list item win_item = new FMenuItem (name, winmenu); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMenuItem"); return; } @@ -663,9 +664,9 @@ void FMenuItem::passMouseEvent ( T widget, const FMouseEvent* ev { _ev = std::make_shared(ev_type, p2, t, b); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); return; } diff --git a/src/fmessagebox.cpp b/src/fmessagebox.cpp index 58174342..097fd554 100644 --- a/src/fmessagebox.cpp +++ b/src/fmessagebox.cpp @@ -24,6 +24,7 @@ #include "final/fapplication.h" #include "final/fbutton.h" +#include "final/flog.h" #include "final/fmessagebox.h" namespace finalcut @@ -256,9 +257,9 @@ inline void FMessageBox::allocation (int button0, int button1, int button2) button[2]->setHeight(1, false); } } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FButton"); return; } } diff --git a/src/fobject.cpp b/src/fobject.cpp index 64eeec48..9649d11d 100644 --- a/src/fobject.cpp +++ b/src/fobject.cpp @@ -60,9 +60,9 @@ FObject::FObject (FObject* parent) { timer_list = new FTimerList; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTimerList"); return; } } diff --git a/src/fstartoptions.cpp b/src/fstartoptions.cpp index 4093f980..1fd35f97 100644 --- a/src/fstartoptions.cpp +++ b/src/fstartoptions.cpp @@ -20,6 +20,8 @@ * . * ***********************************************************************/ +#include "final/fapplication.h" +#include "final/flog.h" #include "final/fstartoptions.h" namespace finalcut @@ -65,9 +67,9 @@ FStartOptions& FStartOptions::getFStartOptions() { start_options = new FStartOptions; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FStartOptions"); std::abort(); } } diff --git a/src/fstring.cpp b/src/fstring.cpp index ab3e51c8..f10e8623 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp @@ -25,6 +25,8 @@ #include #include +#include "final/fapplication.h" +#include "final/flog.h" #include "final/fstring.h" namespace finalcut @@ -1232,9 +1234,9 @@ inline void FString::initLength (std::size_t len) string = new wchar_t[bufsize](); std::wmemset (string, L'\0', bufsize); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("wchar_t[bufsize]"); } } @@ -1263,9 +1265,9 @@ void FString::_assign (const wchar_t s[]) { string = new wchar_t[bufsize](); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("wchar_t[bufsize]"); return; } } @@ -1291,9 +1293,9 @@ void FString::_insert (std::size_t len, const wchar_t s[]) { string = new wchar_t[bufsize](); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << " " << ex.what() << std::endl; + badAllocOutput ("wchar_t[bufsize]"); return; } @@ -1338,9 +1340,9 @@ void FString::_insert ( std::size_t pos { sptr = new wchar_t[bufsize](); // generate new string } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << " " << ex.what() << std::endl; + badAllocOutput ("wchar_t[bufsize]"); return; } @@ -1382,9 +1384,9 @@ void FString::_remove (std::size_t pos, std::size_t len) { sptr = new wchar_t[bufsize](); // generate new string } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << " " << ex.what() << std::endl; + badAllocOutput ("wchar_t[bufsize]"); return; } @@ -1416,9 +1418,9 @@ inline char* FString::wc_to_c_str (const wchar_t s[]) const // Generate a empty string ("") c_string = new char[1](); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << " " << ex.what() << std::endl; + badAllocOutput ("char[1]"); return nullptr; } @@ -1441,9 +1443,9 @@ inline char* FString::wc_to_c_str (const wchar_t s[]) const // pre-initialiaze the whole string with '\0' std::memset (c_string, '\0', std::size_t(dest_size)); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << " " << ex.what() << std::endl; + badAllocOutput ("char[std::size_t(dest_size)]"); return nullptr; } @@ -1473,9 +1475,9 @@ inline wchar_t* FString::c_to_wc_str (const char s[]) const // Generate a empty wide string (L"") return new wchar_t[1](); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << " " << ex.what() << std::endl; + badAllocOutput ("wchar_t[1]"); return nullptr; } } @@ -1493,9 +1495,9 @@ inline wchar_t* FString::c_to_wc_str (const char s[]) const // pre-initialiaze the whole string with '\0' std::wmemset (dest, L'\0', std::size_t(size)); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << " " << ex.what() << std::endl; + badAllocOutput ("wchar_t[std::size_t(size)]"); return nullptr; } diff --git a/src/fsystemimpl.cpp b/src/fsystemimpl.cpp index 31f8b38d..3f8fdef3 100644 --- a/src/fsystemimpl.cpp +++ b/src/fsystemimpl.cpp @@ -3,7 +3,7 @@ * * * This file is part of the Final Cut widget toolkit * * * -* Copyright 2019 Markus Gans * +* Copyright 2019-2020 Markus Gans * * * * The Final Cut is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * @@ -42,6 +42,7 @@ FSystemImpl::FSystemImpl() FSystemImpl::~FSystemImpl() // destructor { } +// public methods of FSystemImpl //---------------------------------------------------------------------- int FSystemImpl::getpwuid_r ( uid_t uid, struct passwd* pwd , char* buf, size_t buflen diff --git a/src/fterm.cpp b/src/fterm.cpp index 04ab4292..1a4146f9 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -31,6 +31,7 @@ #include "final/fcolorpalette.h" #include "final/fkey_map.h" #include "final/fkeyboard.h" +#include "final/flog.h" #include "final/fmouse.h" #include "final/foptiattr.h" #include "final/foptimove.h" @@ -189,9 +190,9 @@ FTermData* FTerm::getFTermData() { data = new FTermData; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTermData"); std::abort(); } } @@ -208,9 +209,9 @@ FSystem* FTerm::getFSystem() { fsys = new FSystemImpl; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTermData"); std::abort(); } } @@ -227,9 +228,9 @@ FOptiMove* FTerm::getFOptiMove() { opti_move = new FOptiMove; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FOptiMove"); std::abort(); } } @@ -246,9 +247,9 @@ FOptiAttr* FTerm::getFOptiAttr() { opti_attr = new FOptiAttr; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FOptiAttr"); std::abort(); } } @@ -265,9 +266,9 @@ FTermDetection* FTerm::getFTermDetection() { term_detection = new FTermDetection; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTermDetection"); std::abort(); } } @@ -284,9 +285,9 @@ FTermXTerminal* FTerm::getFTermXTerminal() { xterm = new FTermXTerminal; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTermXTerminal"); std::abort(); } } @@ -303,9 +304,9 @@ FKeyboard* FTerm::getFKeyboard() { keyboard = new FKeyboard; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FKeyboard"); std::abort(); } } @@ -322,9 +323,9 @@ FMouseControl* FTerm::getFMouseControl() { mouse = new FMouseControl; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseControl"); std::abort(); } } @@ -342,9 +343,9 @@ FTermLinux* FTerm::getFTermLinux() { linux = new FTermLinux; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTermLinux"); std::abort(); } } @@ -362,9 +363,9 @@ FTermFreeBSD* FTerm::getFTermFreeBSD() { freebsd = new FTermFreeBSD; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTermFreeBSD"); std::abort(); } } @@ -382,9 +383,9 @@ FTermOpenBSD* FTerm::getFTermOpenBSD() { openbsd = new FTermOpenBSD; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTermOpenBSD"); std::abort(); } } @@ -403,9 +404,9 @@ FTermDebugData& FTerm::getFTermDebugData() { debug_data = new FTermDebugData; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTermDebugData"); std::abort(); } } @@ -624,7 +625,7 @@ void FTerm::redefineDefaultColors (bool enable) if ( isNewFont() ) // NewFont need the reverse-video attribute return; - xterm->redefineDefaultColors (enable); + getFTermXTerminal()->redefineDefaultColors (enable); } //---------------------------------------------------------------------- @@ -665,7 +666,7 @@ bool FTerm::setVGAFont() { data->setVGAFont(true); // Set font in xterm to vga - xterm->setFont("vga"); + getFTermXTerminal()->setFont("vga"); data->setNewFont(false); } #if defined(__linux__) @@ -700,7 +701,7 @@ bool FTerm::setNewFont() { data->setNewFont(true); // Set font in xterm to 8x16graph - xterm->setFont("8x16graph"); + getFTermXTerminal()->setFont("8x16graph"); } #if defined(__linux__) else if ( isLinuxTerm() ) @@ -739,12 +740,12 @@ bool FTerm::setOldFont() if ( font.getLength() > 2 ) { // restore saved xterm font - xterm->setFont(font); + getFTermXTerminal()->setFont(font); } else { // Set font in xterm to vga - xterm->setFont("vga"); + getFTermXTerminal()->setFont("vga"); } retval = true; @@ -914,7 +915,7 @@ void FTerm::setTermSize (const FSize& size) { // Set xterm size - xterm->setTermSize (size); + getFTermXTerminal()->setTermSize (size); } //---------------------------------------------------------------------- @@ -922,7 +923,7 @@ void FTerm::setTermTitle (const FString& title) { // Set the xterm window title - xterm->setTitle (title); + getFTermXTerminal()->setTitle (title); } //---------------------------------------------------------------------- @@ -1268,10 +1269,10 @@ void FTerm::initScreenSettings() #endif // set xterm underline cursor - xterm->setCursorStyle (fc::blinking_underline); + getFTermXTerminal()->setCursorStyle (fc::blinking_underline); // set xterm color settings to defaults - xterm->setDefaults(); + getFTermXTerminal()->setDefaults(); } //---------------------------------------------------------------------- @@ -1297,7 +1298,7 @@ void FTerm::exitWithMessage (const FString& message) std::fflush (stdout); if ( ! message.isEmpty() ) - std::cerr << "Warning: " << message << std::endl; + FApplication::getLog()->warn(message.c_str()); std::exit (EXIT_FAILURE); } @@ -1322,7 +1323,7 @@ void FTerm::init_global_values (bool disable_alt_screen) data->useAlternateScreen(! disable_alt_screen); // Initialize xterm object - xterm->init(); + getFTermXTerminal()->init(); if ( ! getStartOptions().terminal_detection ) term_detection->setTerminalDetection (false); @@ -1845,9 +1846,9 @@ void FTerm::init_captureFontAndTitle() if ( ! FStartOptions::getFStartOptions().terminal_data_request ) return; - xterm->captureFontAndTitle(); - const auto& font = xterm->getFont(); - const auto& title = xterm->getTitle(); + getFTermXTerminal()->captureFontAndTitle(); + const auto& font = getFTermXTerminal()->getFont(); + const auto& title = getFTermXTerminal()->getTitle(); if ( ! font.isEmpty() ) data->setXtermFont(font); @@ -1899,14 +1900,14 @@ void FTerm::restoreColorPalette() else // 8 colors FColorPalette::reset8ColorPalette (FTerm::setPalette); - xterm->resetColorMap(); + getFTermXTerminal()->resetColorMap(); resetColorMap(); } //---------------------------------------------------------------------- void FTerm::setInsertCursorStyle() { - xterm->setCursorStyle (fc::blinking_underline); + getFTermXTerminal()->setCursorStyle (fc::blinking_underline); setKDECursor(fc::UnderlineCursor); #if defined(__linux__) @@ -1916,13 +1917,13 @@ void FTerm::setInsertCursorStyle() #endif if ( isUrxvtTerminal() ) - xterm->setCursorColor ("rgb:ffff/ffff/ffff"); + getFTermXTerminal()->setCursorColor ("rgb:ffff/ffff/ffff"); } //---------------------------------------------------------------------- void FTerm::setOverwriteCursorStyle() { - xterm->setCursorStyle (fc::steady_block); + getFTermXTerminal()->setCursorStyle (fc::steady_block); setKDECursor(fc::BlockCursor); #if defined(__linux__) @@ -1932,7 +1933,7 @@ void FTerm::setOverwriteCursorStyle() #endif if ( isUrxvtTerminal() ) - xterm->setCursorColor ("rgb:eeee/0000/0000"); + getFTermXTerminal()->setCursorColor ("rgb:eeee/0000/0000"); } //---------------------------------------------------------------------- @@ -2250,7 +2251,7 @@ void FTerm::init (bool disable_alt_screen) // Activate meta key sends escape if ( isXTerminal() ) - xterm->metaSendsESC(true); + getFTermXTerminal()->metaSendsESC(true); // switch to application escape key mode enableApplicationEscKey(); @@ -2429,10 +2430,10 @@ void FTerm::finish() } // Reset xterm color settings to default values - xterm->resetDefaults(); + getFTermXTerminal()->resetDefaults(); // Set xterm full block cursor - xterm->setCursorStyle (fc::steady_block); + getFTermXTerminal()->setCursorStyle (fc::steady_block); // Restore the color palette if ( getStartOptions().color_change ) @@ -2454,7 +2455,7 @@ void FTerm::finish() // Deactivate meta key sends escape if ( isXTerminal() ) - xterm->metaSendsESC(false); + getFTermXTerminal()->metaSendsESC(false); // Switch to the normal screen useNormalScreenBuffer(); @@ -2471,7 +2472,7 @@ void FTerm::finish() const auto& exit_message = data->getExitMessage(); if ( ! exit_message.isEmpty() ) - std::cerr << exit_message << std::endl; + FApplication::getLog()->info(exit_message.c_str()); deallocationValues(); } @@ -2546,9 +2547,11 @@ void FTerm::signal_handler (int signum) init_term_object->finish(); std::fflush (stderr); std::fflush (stdout); - std::cerr << "\nProgram stopped: signal " - << signum - << " (" << strsignal(signum) << ")" << std::endl; + *FApplication::getLog() << FLog::Error + << "\nProgram stopped: signal " + << signum + << " (" << strsignal(signum) << ")" + << std::endl; std::terminate(); default: diff --git a/src/fterm_functions.cpp b/src/fterm_functions.cpp index a28bde33..d90f226c 100644 --- a/src/fterm_functions.cpp +++ b/src/fterm_functions.cpp @@ -27,7 +27,9 @@ #include #include +#include "final/fapplication.h" #include "final/fcharmap.h" +#include "final/flog.h" #include "final/fterm.h" #include "final/ftermbuffer.h" @@ -451,7 +453,8 @@ std::size_t getColumnWidth (const FString& s, std::size_t pos) } catch (const std::out_of_range& ex) { - std::cerr << "Out of Range error: " << ex.what() << std::endl; + *FApplication::getLog() << FLog::Error + << "Out of Range error: " << ex.what() << std::endl; } } diff --git a/src/ftermcap.cpp b/src/ftermcap.cpp index 251a42ec..7e361cd1 100644 --- a/src/ftermcap.cpp +++ b/src/ftermcap.cpp @@ -83,7 +83,7 @@ void FTermcap::termcap() std::vector terminals{}; static constexpr int success = 1; static constexpr int uninitialized = -2; - static char term_buffer[2048]{}; + static char term_buffer[BUF_SIZE]{}; int status = uninitialized; const bool color256 = term_detection->canDisplay256Colors(); @@ -116,9 +116,6 @@ void FTermcap::termcap() ++iter; } - if ( std::strncmp(termtype, "ansi", 4) == 0 ) - term_detection->setAnsiTerminal (true); - termcapError (status); termcapVariables(); } @@ -129,19 +126,21 @@ void FTermcap::termcapError (int status) static constexpr int no_entry = 0; static constexpr int db_not_found = -1; static constexpr int uninitialized = -2; + finalcut::FLog& log = *FApplication::getLog(); if ( status == no_entry || status == uninitialized ) { const char* termtype = fterm_data->getTermType(); - std::cerr << "Unknown terminal: " << termtype << "\n" - << "Check the TERM environment variable\n" - << "Also make sure that the terminal\n" - << "is defined in the termcap/terminfo database.\n"; + log << FLog::Error + << "Unknown terminal: " << termtype << "\n" + << "Check the TERM environment variable\n" + << "Also make sure that the terminal\n" + << "is defined in the termcap/terminfo database.\n"; std::abort(); } else if ( status == db_not_found ) { - std::cerr << "The termcap/terminfo database could not be found.\n"; + log << "The termcap/terminfo database could not be found.\n"; std::abort(); } } diff --git a/src/ftermdetection.cpp b/src/ftermdetection.cpp index cc536aa0..4554f85f 100644 --- a/src/ftermdetection.cpp +++ b/src/ftermdetection.cpp @@ -25,7 +25,9 @@ #endif #include "final/emptyfstring.h" +#include "final/fapplication.h" #include "final/fc.h" +#include "final/flog.h" #include "final/fsystem.h" #include "final/fterm.h" #include "final/ftermdata.h" @@ -377,6 +379,8 @@ void FTermDetection::detectTerminal() if ( ! new_termtype && std::strlen(termtype) == 5 ) new_termtype = "xterm-16color"; } + else if ( std::strncmp(termtype, "ansi", 4) == 0 ) // ANSI detection + terminal_type.ansi = true; // set the new environment variable TERM if ( new_termtype ) @@ -587,9 +591,9 @@ const char* FTermDetection::parseAnswerbackMsg (const char current_termtype[]) { answer_back = new FString(getAnswerbackMsg()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FString"); return nullptr; } @@ -657,9 +661,9 @@ const char* FTermDetection::parseSecDA (const char current_termtype[]) // Secondary device attributes (SEC_DA) <- decTerminalID string sec_da = new FString(getSecDA()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FString"); return current_termtype; } diff --git a/src/ftermlinux.cpp b/src/ftermlinux.cpp index 566cadc8..580f9b99 100644 --- a/src/ftermlinux.cpp +++ b/src/ftermlinux.cpp @@ -22,8 +22,10 @@ #include +#include "final/fapplication.h" #include "final/fc.h" #include "final/fcharmap.h" +#include "final/flog.h" #include "final/fsystem.h" #include "final/fterm.h" #include "final/ftermcap.h" @@ -200,7 +202,7 @@ void FTermLinux::init() } else { - std::cerr << "can not open the console.\n"; + FApplication::getLog()->error("Can not open the console."); std::abort(); } } @@ -553,9 +555,9 @@ bool FTermLinux::getScreenFont() static constexpr std::size_t data_size = 4 * 32 * 512; font.data = new uChar[data_size](); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FString"); return false; } @@ -605,9 +607,9 @@ bool FTermLinux::getUnicodeMap() { screen_unicode_map.entries = new struct unipair[count](); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("unipair[count]"); return false; } @@ -683,9 +685,9 @@ int FTermLinux::setScreenFont ( uChar fontdata[], uInt count { font.data = new uChar[data_size](); // Initialize with 0 } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("uChar[data_size]"); return -1; } diff --git a/src/ftextview.cpp b/src/ftextview.cpp index 35839b15..c5df4b41 100644 --- a/src/ftextview.cpp +++ b/src/ftextview.cpp @@ -178,6 +178,18 @@ void FTextView::scrollTo (int x, int y) updateTerminal(); } +//---------------------------------------------------------------------- +void FTextView::scrollToBegin() +{ + scrollToY (0); +} + +//---------------------------------------------------------------------- +void FTextView::scrollToEnd() +{ + scrollToY (int(getRows() - getTextHeight())); +} + //---------------------------------------------------------------------- void FTextView::hide() { @@ -363,9 +375,9 @@ void FTextView::onMouseDown (FMouseEvent* ev) std::make_shared(fc::MouseDown_Event, p, tp, b); FApplication::sendEvent (parent, _ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); } } } @@ -392,9 +404,9 @@ void FTextView::onMouseUp (FMouseEvent* ev) std::make_shared(fc::MouseUp_Event, p, tp, b); FApplication::sendEvent (parent, _ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); } } } @@ -425,9 +437,9 @@ void FTextView::onMouseMove (FMouseEvent* ev) std::make_shared(fc::MouseMove_Event, p, tp, b); FApplication::sendEvent (parent, _ev.get()); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FMouseEvent"); } } } @@ -577,8 +589,8 @@ inline void FTextView::mapKeyFunctions() key_map[fc::Fkey_right] = [this] { scrollBy (1, 0); }; key_map[fc::Fkey_ppage] = [this] { scrollBy (0, -int(getTextHeight())); }; key_map[fc::Fkey_npage] = [this] { scrollBy (0, int(getTextHeight())); }; - key_map[fc::Fkey_home] = [this] { scrollToY (0); }; - key_map[fc::Fkey_end] = [this] { scrollToY (int(getRows() - getTextHeight())); }; + key_map[fc::Fkey_home] = [this] { scrollToBegin(); }; + key_map[fc::Fkey_end] = [this] { scrollToEnd(); }; } //---------------------------------------------------------------------- diff --git a/src/fvterm.cpp b/src/fvterm.cpp index 71ba9303..751e5d59 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -29,6 +29,7 @@ #include "final/fcharmap.h" #include "final/fcolorpair.h" #include "final/fkeyboard.h" +#include "final/flog.h" #include "final/foptiattr.h" #include "final/foptimove.h" #include "final/fstyle.h" @@ -690,9 +691,9 @@ void FVTerm::createArea ( const FRect& box { area = new FTermArea; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTermArea"); return; } @@ -1383,9 +1384,9 @@ inline bool FVTerm::reallocateTextArea ( FTermArea* area area->changes = new FLineChanges[height]; area->data = new FChar[size]; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocFunctionOutput ("FLineChanges[height] or FChar[size]"); return false; } @@ -1404,9 +1405,9 @@ inline bool FVTerm::reallocateTextArea (FTermArea* area, std::size_t size) { area->data = new FChar[size]; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocFunctionOutput ("FChar[size]"); return false; } @@ -1909,9 +1910,9 @@ void FVTerm::init (bool disable_alt_screen) term_pos = new FPoint(-1, -1); output_buffer = new std::queue; } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FTerm, FPoint, or std::queue"); std::abort(); } diff --git a/src/fwidget.cpp b/src/fwidget.cpp index 38999673..445ca6d6 100644 --- a/src/fwidget.cpp +++ b/src/fwidget.cpp @@ -24,6 +24,7 @@ #include "final/fapplication.h" #include "final/fevent.h" +#include "final/flog.h" #include "final/fmenubar.h" #include "final/fstatusbar.h" #include "final/fstring.h" @@ -1689,9 +1690,9 @@ void FWidget::initRootWidget() always_on_top_list = new FWidgetList(); close_widget = new FWidgetList(); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FWidgetList"); return; } diff --git a/src/include/final/emptyfstring.h b/src/include/final/emptyfstring.h index 6d2beb0f..2c3f9e6a 100644 --- a/src/include/final/emptyfstring.h +++ b/src/include/final/emptyfstring.h @@ -27,6 +27,8 @@ #error "Only can be included directly." #endif +#include "final/fapplication.h" +#include "final/flog.h" #include "final/fstring.h" namespace finalcut @@ -51,6 +53,7 @@ public: // Disable copy assignment operator (=) emptyFString& operator = (const emptyFString&) = delete; + static const FString getClassName(); static bool isNull(); static const FString& get(); static void clear(); @@ -61,6 +64,10 @@ private: }; // emptyFString inline functions +//---------------------------------------------------------------------- +inline const FString emptyFString::getClassName() +{ return "emptyFString"; } + //---------------------------------------------------------------------- inline bool emptyFString::isNull() { @@ -76,9 +83,9 @@ inline const FString& emptyFString::get() { empty_string = new FString(""); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocOutput ("FString"); } } diff --git a/src/include/final/fapplication.h b/src/include/final/fapplication.h index 52f7a8e7..fc51e84c 100644 --- a/src/include/final/fapplication.h +++ b/src/include/final/fapplication.h @@ -68,11 +68,12 @@ namespace finalcut { // class forward declaration -class FEvent; class FAccelEvent; class FCloseEvent; +class FEvent; class FFocusEvent; class FKeyEvent; +class FLog; class FMouseEvent; class FStartOptions; class FTimerEvent; @@ -106,6 +107,10 @@ class FApplication : public FWidget int getArgc() const; char** getArgv() const; static FApplication* getApplicationObject(); + static std::shared_ptr& getLog(); + + // Mutator + static void setLog (const std::shared_ptr&); // Inquiry static bool isQuit(); @@ -177,6 +182,7 @@ class FApplication : public FWidget void processMouseEvent(); void processResizeEvent(); void processCloseWidget(); + void processLogger(); bool processNextEvent(); void performTimerAction (FObject*, FEvent*) override; static bool isEventProcessable (const FObject*, const FEvent*); diff --git a/src/include/final/final.h b/src/include/final/final.h index e829a454..fe235835 100644 --- a/src/include/final/final.h +++ b/src/include/final/final.h @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/include/final/flog.h b/src/include/final/flog.h new file mode 100644 index 00000000..73b49cee --- /dev/null +++ b/src/include/final/flog.h @@ -0,0 +1,129 @@ +/*********************************************************************** +* flog.h - Interface of the FINAL CUT logger * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2020 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public License * +* as published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* The Final Cut 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 Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +/* Standalone class + * ════════════════ + * + * ▕▔▔▔▔▔▔▏ + * ▕ FLog ▏ + * ▕▁▁▁▁▁▁▏ + */ + +#ifndef FLOG_H +#define FLOG_H + +#if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT) + #error "Only can be included directly." +#endif + +#include +#include +#include +#include +#include + +#include + +namespace finalcut +{ + +using namespace std::placeholders; + +//---------------------------------------------------------------------- +// class FLog +//---------------------------------------------------------------------- + +class FLog : public std::stringbuf +{ + public: + // Using-declaration + using FLogPrint = std::function; + + // Enumerations + enum LogLevel + { + Info, Warn, Error, Debug + }; + + enum LineEnding + { + LF, CR, CRLF + }; + + + // Constructor + FLog(); + + // Destructor + ~FLog() override; + + template + FLog& operator << (const T& s); + FLog& operator << (std::ostream&(*)(std::ostream&)); + FLog& operator << (LogLevel); + + virtual const FString getClassName() const; + virtual void info (const std::string&) = 0; + virtual void warn (const std::string&) = 0; + virtual void error (const std::string&) = 0; + virtual void debug (const std::string&) = 0; + virtual void setOutputStream (const std::ostream&) = 0; + virtual void setLineEnding (LineEnding) = 0; + virtual void enableTimestamp() = 0; + virtual void disableTimestamp() = 0; + + protected: + int sync() override; + + // Data member + LogLevel level{Info}; + LineEnding end_of_line{CRLF}; + + private: + // Data member + FLogPrint current_log{std::bind(&FLog::info, this, _1)}; + std::ostream stream{this}; +}; + +// FLog inline functions +//---------------------------------------------------------------------- +template +inline FLog& FLog::operator << (const T& s) +{ + stream << s; + return *this; +} + +//---------------------------------------------------------------------- +inline FLog& FLog::operator << (std::ostream&(*pf)(std::ostream&)) +{ + pf(stream); + return *this; +} + +//---------------------------------------------------------------------- +inline const FString FLog::getClassName() const +{ return "FLog"; } + +} // namespace finalcut + +#endif // FLOG_H diff --git a/src/include/final/flogger.h b/src/include/final/flogger.h new file mode 100644 index 00000000..e4dde187 --- /dev/null +++ b/src/include/final/flogger.h @@ -0,0 +1,138 @@ +/*********************************************************************** +* flogger.h - The FINAL CUT text logger * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2020 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public License * +* as published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* The Final Cut 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 Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +/* Standalone class + * ════════════════ + * + * ▕▔▔▔▔▔▔▔▔▔▏ + * ▕ FLogger ▏ + * ▕▁▁▁▁▁▁▁▁▁▏ + */ + +#ifndef FLOGGER_H +#define FLOGGER_H + +#if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT) + #error "Only can be included directly." +#endif + +#include +#include +#include +#include + +#include +#include + +#include "final/flog.h" + +namespace finalcut +{ + +//---------------------------------------------------------------------- +// class FLogger +//---------------------------------------------------------------------- + +class FLogger : public FLog +{ + public: + // Constructor + FLogger(); + + // Destructor + ~FLogger() override; + + // Methods + const FString getClassName() const override; + void info (const std::string&) override; + void warn (const std::string&) override; + void error (const std::string&) override; + void debug (const std::string&) override; + void setOutputStream (const std::ostream&) override; + void setLineEnding (LineEnding) override; + void enableTimestamp() override; + void disableTimestamp() override; + + private: + // Methods + void newlineReplace (std::string&, const std::string&); + const std::string getTimeString(); + const std::string getEOL(); + void printLogLine (const std::string&); + + // Data member + bool timestamp{false}; + std::ostream output{std::cerr.rdbuf()}; +}; + +// FLogger inline functions +//---------------------------------------------------------------------- +inline const FString FLogger::getClassName() const +{ return "FLogger"; } + +//---------------------------------------------------------------------- +inline void FLogger::info (const std::string& msg) +{ + level = Info; + printLogLine (msg); +} + +//---------------------------------------------------------------------- +inline void FLogger::warn (const std::string& msg) +{ + level = Warn; + printLogLine (msg); +} + +//---------------------------------------------------------------------- +inline void FLogger::error (const std::string& msg) +{ + level = Error; + printLogLine (msg); +} + +//---------------------------------------------------------------------- +inline void FLogger::debug (const std::string& msg) +{ + level = Debug; + printLogLine (msg); +} + +//---------------------------------------------------------------------- +inline void FLogger::setOutputStream (const std::ostream& os) +{ output.rdbuf(os.rdbuf()); } + +//---------------------------------------------------------------------- +inline void FLogger::setLineEnding (LineEnding eol) +{ end_of_line = eol; } + +//---------------------------------------------------------------------- +inline void FLogger::enableTimestamp() +{ timestamp = true; } + +//---------------------------------------------------------------------- +inline void FLogger::disableTimestamp() +{ timestamp = false; } + +} // namespace finalcut + +#endif // FLOGGER_H diff --git a/src/include/final/fmessagebox.h b/src/include/final/fmessagebox.h index de13ce09..0e6fea31 100644 --- a/src/include/final/fmessagebox.h +++ b/src/include/final/fmessagebox.h @@ -169,8 +169,8 @@ inline const FString FMessageBox::getClassName() const //---------------------------------------------------------------------- inline const FString FMessageBox::getTitlebarText() const { - const FString& tb_text = FDialog::getText(); // initialize text - return tb_text; + const FString& title = FDialog::getText(); // initialize text + return title; } //---------------------------------------------------------------------- diff --git a/src/include/final/fobject.h b/src/include/final/fobject.h index 2bab65e4..0e68c500 100644 --- a/src/include/final/fobject.h +++ b/src/include/final/fobject.h @@ -48,6 +48,8 @@ #include #include +#include "final/fstring.h" + namespace finalcut { diff --git a/src/include/final/fscrollbar.h b/src/include/final/fscrollbar.h index 61eb4635..50337496 100644 --- a/src/include/final/fscrollbar.h +++ b/src/include/final/fscrollbar.h @@ -50,6 +50,8 @@ #include #include +#include "final/fapplication.h" +#include "final/flog.h" #include "final/fwidget.h" namespace finalcut @@ -180,9 +182,9 @@ void initScrollbar ( FScrollbarPtr& bar { bar = std::make_shared(o, cb_instance); } - catch (const std::bad_alloc& ex) + catch (const std::bad_alloc&) { - std::cerr << bad_alloc_str << ex.what() << std::endl; + badAllocFunctionOutput ("FScrollbar"); return; } diff --git a/src/include/final/fstartoptions.h b/src/include/final/fstartoptions.h index b9e7bac1..b5ca6bb9 100644 --- a/src/include/final/fstartoptions.h +++ b/src/include/final/fstartoptions.h @@ -64,7 +64,7 @@ class FStartOptions final FStartOptions& operator = (const FStartOptions&) = delete; // Accessors - const FString getClassName(); + static const FString getClassName(); static FStartOptions& getFStartOptions(); // Mutator diff --git a/src/include/final/fstring.h b/src/include/final/fstring.h index 91c520ad..e7984ba4 100644 --- a/src/include/final/fstring.h +++ b/src/include/final/fstring.h @@ -162,7 +162,7 @@ class FString operator const char* () const { return c_str(); } // Accessor - virtual const FString getClassName(); + virtual const FString getClassName() const; // inquiries bool isNull() const; @@ -370,7 +370,7 @@ inline bool FString::operator > (const CharT& s) const } //---------------------------------------------------------------------- -inline const FString FString::getClassName() +inline const FString FString::getClassName() const { return "FString"; } //---------------------------------------------------------------------- diff --git a/src/include/final/fsystem.h b/src/include/final/fsystem.h index 483decb3..38b98868 100644 --- a/src/include/final/fsystem.h +++ b/src/include/final/fsystem.h @@ -78,5 +78,3 @@ class FSystem } // namespace finalcut #endif // FSYSTEM_H - - diff --git a/src/include/final/fterm.h b/src/include/final/fterm.h index 7f3f2e8f..948d6af6 100644 --- a/src/include/final/fterm.h +++ b/src/include/final/fterm.h @@ -173,7 +173,7 @@ class FTerm final FTerm& operator = (const FTerm&) = delete; // Accessors - const FString getClassName() const; + static const FString getClassName(); static std::size_t getLineNumber(); static std::size_t getColumnNumber(); static const FString getKeyName (FKey); @@ -405,7 +405,7 @@ std::size_t getColumnWidth (const FTermBuffer&); // FTerm inline functions //---------------------------------------------------------------------- -inline const FString FTerm::getClassName() const +inline const FString FTerm::getClassName() { return "FTerm"; } //---------------------------------------------------------------------- diff --git a/src/include/final/ftermcap.h b/src/include/final/ftermcap.h index 1a8c3cb9..3d26e3ac 100644 --- a/src/include/final/ftermcap.h +++ b/src/include/final/ftermcap.h @@ -126,6 +126,9 @@ class FTermcap final static tcap_map strings[]; private: + // Constant + static constexpr std::size_t BUF_SIZE{2048}; + // Methods static void termcap(); static void termcapError (int); @@ -140,7 +143,7 @@ class FTermcap final static FSystem* fsystem; static FTermData* fterm_data; static FTermDetection* term_detection; - static char string_buf[2048]; + static char string_buf[BUF_SIZE]; }; @@ -153,35 +156,35 @@ inline const FString FTermcap::getClassName() const template bool FTermcap::getFlag (const CharT& cap) { - return tgetflag(C_STR(cap)); + return ::tgetflag(C_STR(cap)); } //---------------------------------------------------------------------- template int FTermcap::getNumber (const CharT& cap) { - return tgetnum(C_STR(cap)); + return ::tgetnum(C_STR(cap)); } //---------------------------------------------------------------------- template char* FTermcap::getString (const CharT& cap) { - return tgetstr(C_STR(cap), reinterpret_cast(&string_buf)); + return ::tgetstr(C_STR(cap), reinterpret_cast(&string_buf)); } //---------------------------------------------------------------------- template char* FTermcap::encodeMotionParameter (const CharT& cap, int col, int row) { - return tgoto(C_STR(cap), col, row); + return ::tgoto(C_STR(cap), col, row); } //---------------------------------------------------------------------- template inline char* FTermcap::encodeParameter (const CharT& cap, Args&&... args) { - return tparm (C_STR(cap), std::forward(args)...); + return ::tparm (C_STR(cap), std::forward(args)...); } //---------------------------------------------------------------------- diff --git a/src/include/final/ftermdata.h b/src/include/final/ftermdata.h index 93b0b3e4..d14e3d52 100644 --- a/src/include/final/ftermdata.h +++ b/src/include/final/ftermdata.h @@ -373,5 +373,3 @@ inline void FTermData::setFramebufferBpp (int bpp) } // namespace finalcut #endif // FTERMDATA_H - - diff --git a/src/include/final/ftermdetection.h b/src/include/final/ftermdetection.h index d68ca07c..f17786d3 100644 --- a/src/include/final/ftermdetection.h +++ b/src/include/final/ftermdetection.h @@ -91,7 +91,7 @@ class FTermDetection final FTermDetection& operator = (const FTermDetection&) = delete; // Accessor - const FString getClassName() const; + static const FString getClassName(); static const char* getTermType(); static int getGnomeTerminalID(); FTerminalType& getTermTypeStruct(); @@ -240,7 +240,7 @@ struct FTermDetection::secondaryDA // FTermDetection inline functions //---------------------------------------------------------------------- -inline const FString FTermDetection::getClassName() const +inline const FString FTermDetection::getClassName() { return "FTermDetection"; } //---------------------------------------------------------------------- diff --git a/src/include/final/ftextview.h b/src/include/final/ftextview.h index d968a8d4..859c108c 100644 --- a/src/include/final/ftextview.h +++ b/src/include/final/ftextview.h @@ -104,6 +104,8 @@ class FTextView : public FWidget void scrollToY (int); void scrollTo (const FPoint&); void scrollTo (int, int); + void scrollToBegin(); + void scrollToEnd(); void scrollBy (int, int); // Methods diff --git a/src/include/final/ftypes.h b/src/include/final/ftypes.h index 395a8bd5..f20ad667 100644 --- a/src/include/final/ftypes.h +++ b/src/include/final/ftypes.h @@ -37,6 +37,23 @@ #define null nullptr +#define badAllocFunctionOutput(object_name) \ + *FApplication::getLog() << FLog::Error \ + << "Not enough memory to alloc " \ + << (object_name) \ + << " in " \ + << __func__ << std::endl; + +#define badAllocOutput(object_name) \ + *FApplication::getLog() << FLog::Error \ + << "Not enough memory to alloc " \ + << (object_name) \ + << " in " \ + << getClassName() \ + << "::" \ + << __func__ << std::endl; + +//F_METHOD_CALLBACK namespace { @@ -69,9 +86,6 @@ typedef void* FDataPtr; namespace finalcut { -const char* const bad_alloc_str = \ - "not enough memory to alloc "; - template struct is_negative { diff --git a/src/include/final/fwidget.h b/src/include/final/fwidget.h index 348ec09a..ada77850 100644 --- a/src/include/final/fwidget.h +++ b/src/include/final/fwidget.h @@ -94,12 +94,12 @@ #include #include -#include "final/fvterm.h" #include "final/fobject.h" #include "final/fpoint.h" #include "final/frect.h" #include "final/fsize.h" #include "final/ftypes.h" +#include "final/fvterm.h" // Callback macros #define F_FUNCTION_CALLBACK(h) \ diff --git a/test/Makefile.am b/test/Makefile.am index a2ff0559..b482d451 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -21,6 +21,7 @@ noinst_PROGRAMS = \ fcolorpair_test \ fstyle_test \ fstring_test \ + flogger_test \ fsize_test \ fpoint_test \ frect_test @@ -39,6 +40,7 @@ foptiattr_test_SOURCES = foptiattr-test.cpp fcolorpair_test_SOURCES = fcolorpair-test.cpp fstyle_test_SOURCES = fstyle-test.cpp fstring_test_SOURCES = fstring-test.cpp +flogger_test_SOURCES = flogger-test.cpp fsize_test_SOURCES = fsize-test.cpp fpoint_test_SOURCES = fpoint-test.cpp frect_test_SOURCES = frect-test.cpp @@ -57,6 +59,7 @@ TESTS = fobject_test \ fcolorpair_test \ fstyle_test \ fstring_test \ + flogger_test \ fsize_test \ fpoint_test \ frect_test diff --git a/test/flogger-test.cpp b/test/flogger-test.cpp new file mode 100644 index 00000000..ed3dcd81 --- /dev/null +++ b/test/flogger-test.cpp @@ -0,0 +1,353 @@ +/*********************************************************************** +* flogger-test.cpp - FLogger unit tests * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2020 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public License * +* as published by the Free Software Foundation; either version 3 of * +* the License, or (at your option) any later version. * +* * +* The Final Cut 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 Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this program. If not, see * +* . * +***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +//---------------------------------------------------------------------- +// class FLoggerTest +//---------------------------------------------------------------------- +class myLogger : public finalcut::FLog +{ + public: + void info (const std::string& entry) override + { + output << " Info: " << entry << std::endl; + } + + void warn (const std::string& entry) override + { + output << " Warn: " << entry << std::endl; + } + + void error (const std::string& entry) override + { + output << "Error: " << entry << std::endl; + } + + void debug (const std::string& entry) override + { + output << "Debug: " << entry << std::endl; + } + + void setOutputStream (const std::ostream& os) override + { output.rdbuf(os.rdbuf()); } + + void setLineEnding (LineEnding) override + { } + + void enableTimestamp() override + { } + + void disableTimestamp() override + { } + + private: + // Data member + std::ostream output{std::cerr.rdbuf()}; +}; + +//---------------------------------------------------------------------- +// class FLoggerTest +//---------------------------------------------------------------------- + +class FLoggerTest : public CPPUNIT_NS::TestFixture +{ + public: + FLoggerTest() + { } + + protected: + void classNameTest(); + void defaultObjectTest(); + void lineEndingTest(); + void timestampTest(); + void fileTest(); + void applicationObjectTest(); + + private: + // Adds code needed to register the test suite + CPPUNIT_TEST_SUITE (FLoggerTest); + + // Add a methods to the test suite + CPPUNIT_TEST (classNameTest); + CPPUNIT_TEST (defaultObjectTest); + CPPUNIT_TEST (lineEndingTest); + CPPUNIT_TEST (timestampTest); + CPPUNIT_TEST (fileTest); + CPPUNIT_TEST (applicationObjectTest); + + // End of test suite definition + CPPUNIT_TEST_SUITE_END(); +}; + +//---------------------------------------------------------------------- +void FLoggerTest::classNameTest() +{ + finalcut::FLogger log; + const finalcut::FString& classname = log.getClassName(); + CPPUNIT_ASSERT ( classname == "FLogger" ); +} + +//---------------------------------------------------------------------- +void FLoggerTest::defaultObjectTest() +{ + finalcut::FLogger log{}; + std::ostringstream buf{}; + log.setOutputStream(buf); + log << "Hello, World!" << std::flush; // Default level is "Info" + CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log << "Hel" << "lo," << " Wor" << "ld!" << std::flush; // Several parts + CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log << "Hello, World!" << std::endl; // std::endl + CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\n\r\n" ); + buf.str(""); // Clear buffer + + log << finalcut::FLog::Info << "Hello, World!" << std::flush; + CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log << finalcut::FLog::Warn << "Hello, World!" << std::flush; + CPPUNIT_ASSERT ( buf.str() == "[WARNING] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log << "Hello, World!" << std::flush; // Last level was "Warn" + CPPUNIT_ASSERT ( buf.str() == "[WARNING] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log << finalcut::FLog::Error << "Hello, World!" << std::flush; + CPPUNIT_ASSERT ( buf.str() == "[ERROR] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log << "Hello, World!" << std::flush; // Last level was "Error" + CPPUNIT_ASSERT ( buf.str() == "[ERROR] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log << finalcut::FLog::Debug << "Hello, World!" << std::flush; + CPPUNIT_ASSERT ( buf.str() == "[DEBUG] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log << "Hello, World!" << std::flush; // Last level was "Debug" + CPPUNIT_ASSERT ( buf.str() == "[DEBUG] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + // Without stream + log.info("Hello, World!"); + CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log.warn("Hello, World!"); + CPPUNIT_ASSERT ( buf.str() == "[WARNING] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log.error("Hello, World!"); + CPPUNIT_ASSERT ( buf.str() == "[ERROR] Hello, World!\r\n" ); + buf.str(""); // Clear buffer + + log.debug("Hello, World!"); + CPPUNIT_ASSERT ( buf.str() == "[DEBUG] Hello, World!\r\n" ); + buf.str(""); // Clear buffer +} + +//---------------------------------------------------------------------- +void FLoggerTest::lineEndingTest() +{ + finalcut::FLogger log{}; + std::ostringstream buf{}; + log.setOutputStream(buf); + + log.info("Line endings"); // Default = CRLF + CPPUNIT_ASSERT ( buf.str() == "[INFO] Line endings\r\n" ); + buf.str(""); // Clear buffer + + log.setLineEnding(finalcut::FLog::LF); + log.warn("Line endings"); + CPPUNIT_ASSERT ( buf.str() == "[WARNING] Line endings\n" ); + buf.str(""); // Clear buffer + + log.setLineEnding(finalcut::FLog::CR); + log.error("Line endings"); + CPPUNIT_ASSERT ( buf.str() == "[ERROR] Line endings\r" ); + buf.str(""); // Clear buffer + + log.setLineEnding(finalcut::FLog::CRLF); + log.debug("Line endings"); + CPPUNIT_ASSERT ( buf.str() == "[DEBUG] Line endings\r\n" ); + buf.str(""); // Clear buffer +} + +//---------------------------------------------------------------------- +void FLoggerTest::timestampTest() +{ + finalcut::FLogger log{}; + std::ostringstream buf{}; + log.setOutputStream(buf); + + log.info("Timestamp"); + std::size_t length = buf.str().length(); + CPPUNIT_ASSERT ( buf.str() == "[INFO] Timestamp\r\n" ); + CPPUNIT_ASSERT ( length == 18 ); + buf.str(""); // Clear buffer + + log.enableTimestamp(); + log.info("Timestamp"); + length = buf.str().length(); + CPPUNIT_ASSERT ( buf.str().substr(length - 18) == "[INFO] Timestamp\r\n" ); + CPPUNIT_ASSERT ( length > 40 ); + buf.str(""); // Clear buffer + + log.disableTimestamp(); + log.info("Timestamp"); + length = buf.str().length(); + CPPUNIT_ASSERT ( buf.str() == "[INFO] Timestamp\r\n" ); + CPPUNIT_ASSERT ( length == 18 ); + buf.str(""); // Clear buffer +} + +//---------------------------------------------------------------------- +void FLoggerTest::fileTest() +{ + std::string filename = "test.log"; + + { + finalcut::FLogger log{}; + std::ofstream file_stream(filename, std::ofstream::out); + log.setLineEnding (finalcut::FLog::LF); + log.setOutputStream(file_stream); + + log.info("test1"); + log.warn("test2"); + log.error("test3"); + log.debug("test4"); + log << finalcut::FLog::Info << "streaming test1"; + log << finalcut::FLog::Warn << "streaming test2"; + log << finalcut::FLog::Error << "streaming test3"; + log << finalcut::FLog::Debug << "streaming test4" << std::flush; + + if ( file_stream.is_open() ) + file_stream.close(); + } // End of logging + + + std::string strings[] = + { + "[INFO] test1", + "[WARNING] test2", + "[ERROR] test3", + "[DEBUG] test4", + "[INFO] streaming test1", + "[WARNING] streaming test2", + "[ERROR] streaming test3", + "[DEBUG] streaming test4", + "" + }; + + std::string line{}; + std::ifstream file_stream{filename}; + std::size_t i{0}; + + while ( ! file_stream.eof() && file_stream.good() ) + { + getline(file_stream, line); + CPPUNIT_ASSERT ( line == strings[i] ); + i++; + } + + if ( file_stream.is_open() ) + file_stream.close(); + + remove("test.log"); // Delete file +} + +//---------------------------------------------------------------------- +void FLoggerTest::applicationObjectTest() +{ + std::shared_ptr log = finalcut::FApplication::getLog(); + std::ostringstream buf{}; + log->setOutputStream(buf); + + log->info("test1"); + CPPUNIT_ASSERT ( buf.str() == "[INFO] test1\r\n" ); + buf.str(""); // Clear buffer + + log->warn("test2"); + CPPUNIT_ASSERT ( buf.str() == "[WARNING] test2\r\n" ); + buf.str(""); // Clear buffer + + log->error("test3"); + CPPUNIT_ASSERT ( buf.str() == "[ERROR] test3\r\n" ); + buf.str(""); // Clear buffer + + log->debug("test4"); + CPPUNIT_ASSERT ( buf.str() == "[DEBUG] test4\r\n" ); + buf.str(""); // Clear buffer + + *log << "test5" << std::flush; + CPPUNIT_ASSERT ( buf.str() == "[INFO] test5\r\n" ); + buf.str(""); // Clear buffer + + *log << finalcut::FLog::Error << "test6" << std::flush; + CPPUNIT_ASSERT ( buf.str() == "[ERROR] test6\r\n" ); + buf.str(""); // Clear buffer + + // Replace the logger with another one + finalcut::FApplication::setLog(std::make_shared()); + log = finalcut::FApplication::getLog(); + log->setOutputStream(buf); + + log->info("myLogger 1"); + CPPUNIT_ASSERT ( buf.str() == " Info: myLogger 1\n" ); + buf.str(""); // Clear buffer + + log->warn("myLogger 2"); + CPPUNIT_ASSERT ( buf.str() == " Warn: myLogger 2\n" ); + buf.str(""); // Clear buffer + + log->error("myLogger 3"); + CPPUNIT_ASSERT ( buf.str() == "Error: myLogger 3\n" ); + buf.str(""); // Clear buffer + + log->debug("myLogger 4"); + CPPUNIT_ASSERT ( buf.str() == "Debug: myLogger 4\n" ); + buf.str(""); // Clear buffer +} + + +// Put the test suite in the registry +CPPUNIT_TEST_SUITE_REGISTRATION (FLoggerTest); + +// The general unit test main part +#include +