diff options
Diffstat (limited to 'Source/CursesDialog')
80 files changed, 13165 insertions, 0 deletions
diff --git a/Source/CursesDialog/.NoDartCoverage b/Source/CursesDialog/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/Source/CursesDialog/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/Source/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt new file mode 100644 index 0000000..c24ee76 --- /dev/null +++ b/Source/CursesDialog/CMakeLists.txt @@ -0,0 +1,63 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +add_executable(ccmake + ccmake.cxx + cmCursesBoolWidget.cxx + cmCursesCacheEntryComposite.cxx + cmCursesColor.cxx + cmCursesDummyWidget.cxx + cmCursesFilePathWidget.cxx + cmCursesForm.cxx + cmCursesLabelWidget.cxx + cmCursesLongMessageForm.cxx + cmCursesMainForm.cxx + cmCursesOptionsWidget.cxx + cmCursesPathWidget.cxx + cmCursesStringWidget.cxx + cmCursesWidget.cxx + ) +target_include_directories(ccmake PRIVATE ${CURSES_INCLUDE_PATH}) +set(CMAKE_REQUIRED_INCLUDES ${CURSES_INCLUDE_PATH}) +target_link_libraries(ccmake CMakeLib) +if(CMAKE_USE_SYSTEM_FORM) + find_path(CURSES_FORM_INCLUDE_DIR NAMES form.h HINTS ${CURSES_INCLUDE_PATH} ${CURSES_INCLUDE_PATH}/ncurses) + if(CURSES_FORM_INCLUDE_DIR) + target_include_directories(ccmake PRIVATE ${CURSES_FORM_INCLUDE_DIR}) + list(APPEND CMAKE_REQUIRED_INCLUDES ${CURSES_FORM_INCLUDE_DIR}) + endif() + target_link_libraries(ccmake + ${CURSES_FORM_LIBRARY} + ${CURSES_LIBRARY} + ) + set(CMAKE_REQUIRED_LIBRARIES + ${CURSES_FORM_LIBRARY} + ${CURSES_LIBRARY} + ) + if(CURSES_EXTRA_LIBRARY) + target_link_libraries(ccmake ${CURSES_EXTRA_LIBRARY}) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURSES_EXTRA_LIBRARY}) + endif() +else() + target_link_libraries(ccmake cmForm) + get_target_property(cmFormIncludeDirs cmForm INTERFACE_INCLUDE_DIRECTORIES) + list(APPEND CMAKE_REQUIRED_INCLUDES ${cmFormIncludeDirs}) + get_target_property(cmFormLibraries cmForm INTERFACE_LINK_LIBRARIES) + set(CMAKE_REQUIRED_LIBRARIES ${cmFormLibraries}) +endif() + +include(CheckSymbolExists) +check_symbol_exists(use_default_colors + "form.h" + HAVE_CURSES_USE_DEFAULT_COLORS) +if(HAVE_CURSES_USE_DEFAULT_COLORS) + set_source_files_properties(cmCursesColor.cxx + PROPERTIES COMPILE_DEFINITIONS HAVE_CURSES_USE_DEFAULT_COLORS) +endif() + +if(CMake_JOB_POOL_LINK_BIN) + set_property(TARGET ccmake PROPERTY JOB_POOL_LINK "link-bin") +endif() + +CMake_OPTIONAL_COMPONENT(ccmake) +install(TARGETS ccmake DESTINATION ${CMAKE_BIN_DIR} ${COMPONENT}) diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx new file mode 100644 index 0000000..9a26db5 --- /dev/null +++ b/Source/CursesDialog/ccmake.cxx @@ -0,0 +1,200 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include <csignal> +#include <cstring> +#include <iostream> +#include <string> +#include <vector> + +#include "cmsys/Encoding.hxx" + +#include "cmCursesColor.h" +#include "cmCursesForm.h" +#include "cmCursesMainForm.h" +#include "cmCursesStandardIncludes.h" +#include "cmDocumentation.h" +#include "cmDocumentationEntry.h" // IWYU pragma: keep +#include "cmState.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmake.h" + +static const char* cmDocumentationName[][2] = { + { nullptr, " ccmake - Curses Interface for CMake." }, + { nullptr, nullptr } +}; + +static const char* cmDocumentationUsage[][2] = { + { nullptr, + " ccmake <path-to-source>\n" + " ccmake <path-to-existing-build>" }, + { nullptr, + "Specify a source directory to (re-)generate a build system for " + "it in the current working directory. Specify an existing build " + "directory to re-generate its build system." }, + { nullptr, nullptr } +}; + +static const char* cmDocumentationUsageNote[][2] = { + { nullptr, "Run 'ccmake --help' for more information." }, + { nullptr, nullptr } +}; + +static const char* cmDocumentationOptions[][2] = { + CMAKE_STANDARD_OPTIONS_TABLE, + { nullptr, nullptr } +}; + +cmCursesForm* cmCursesForm::CurrentForm = nullptr; + +extern "C" { + +void onsig(int /*unused*/) +{ + if (cmCursesForm::CurrentForm) { + endwin(); + initscr(); /* Initialization */ + noecho(); /* Echo off */ + cbreak(); /* nl- or cr not needed */ + keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ + refresh(); + int x; + int y; + getmaxyx(stdscr, y, x); + cmCursesForm::CurrentForm->Render(1, 1, x, y); + cmCursesForm::CurrentForm->UpdateStatusBar(); + } + signal(SIGWINCH, onsig); +} +} + +int main(int argc, char const* const* argv) +{ + cmSystemTools::EnsureStdPipes(); + cmsys::Encoding::CommandLineArguments encoding_args = + cmsys::Encoding::CommandLineArguments::Main(argc, argv); + argc = encoding_args.argc(); + argv = encoding_args.argv(); + + cmSystemTools::InitializeLibUV(); + cmSystemTools::FindCMakeResources(argv[0]); + cmDocumentation doc; + doc.addCMakeStandardDocSections(); + if (doc.CheckOptions(argc, argv)) { + cmake hcm(cmake::RoleInternal, cmState::Unknown); + hcm.SetHomeDirectory(""); + hcm.SetHomeOutputDirectory(""); + hcm.AddCMakePaths(); + auto generators = hcm.GetGeneratorsDocumentation(); + doc.SetName("ccmake"); + doc.SetSection("Name", cmDocumentationName); + doc.SetSection("Usage", cmDocumentationUsage); + if (argc == 1) { + doc.AppendSection("Usage", cmDocumentationUsageNote); + } + doc.AppendSection("Generators", generators); + doc.PrependSection("Options", cmDocumentationOptions); + return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; + } + + bool debug = false; + unsigned int i; + int j; + std::vector<std::string> args; + for (j = 0; j < argc; ++j) { + if (strcmp(argv[j], "-debug") == 0) { + debug = true; + } else { + args.emplace_back(argv[j]); + } + } + + std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory(); + for (i = 1; i < args.size(); ++i) { + std::string const& arg = args[i]; + if (cmHasPrefix(arg, "-B")) { + cacheDir = arg.substr(2); + } + } + + cmSystemTools::DisableRunCommandOutput(); + + if (debug) { + cmCursesForm::DebugStart(); + } + + initscr(); /* Initialization */ + noecho(); /* Echo off */ + cbreak(); /* nl- or cr not needed */ + keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ + cmCursesColor::InitColors(); + + signal(SIGWINCH, onsig); + + int x; + int y; + getmaxyx(stdscr, y, x); + if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) { + endwin(); + std::cerr << "Window is too small. A size of at least " + << cmCursesMainForm::MIN_WIDTH << " x " + << cmCursesMainForm::MIN_HEIGHT << " is required to run ccmake." + << std::endl; + return 1; + } + + cmCursesMainForm* myform; + + myform = new cmCursesMainForm(args, x); + if (myform->LoadCache(cacheDir.c_str())) { + curses_clear(); + touchwin(stdscr); + endwin(); + delete myform; + std::cerr << "Error running cmake::LoadCache(). Aborting.\n"; + return 1; + } + + /* + * The message is stored in a list by the form which will be + * joined by '\n' before display. + * Removing any trailing '\n' avoid extra empty lines in the final results + */ + auto cleanMessage = [](const std::string& message) -> std::string { + auto msg = message; + if (!msg.empty() && msg.back() == '\n') { + msg.pop_back(); + } + return msg; + }; + cmSystemTools::SetMessageCallback( + [&](const std::string& message, const char* title) { + myform->AddError(cleanMessage(message), title); + }); + cmSystemTools::SetStderrCallback([&](const std::string& message) { + myform->AddError(cleanMessage(message), ""); + }); + cmSystemTools::SetStdoutCallback([&](const std::string& message) { + myform->UpdateProgress(cleanMessage(message), -1); + }); + + cmCursesForm::CurrentForm = myform; + + myform->InitializeUI(); + if (myform->Configure(1) == 0) { + myform->Render(1, 1, x, y); + myform->HandleInput(); + } + + // Need to clean-up better + curses_clear(); + touchwin(stdscr); + endwin(); + delete cmCursesForm::CurrentForm; + cmCursesForm::CurrentForm = nullptr; + + std::cout << std::endl << std::endl; + + return 0; +} diff --git a/Source/CursesDialog/cmCursesBoolWidget.cxx b/Source/CursesDialog/cmCursesBoolWidget.cxx new file mode 100644 index 0000000..c4dbed8 --- /dev/null +++ b/Source/CursesDialog/cmCursesBoolWidget.cxx @@ -0,0 +1,64 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesBoolWidget.h" + +#include <string> + +#include "cmCursesColor.h" +#include "cmCursesWidget.h" +#include "cmStateTypes.h" + +cmCursesBoolWidget::cmCursesBoolWidget(int width, int height, int left, + int top) + : cmCursesWidget(width, height, left, top) +{ + this->Type = cmStateEnums::BOOL; + if (!cmCursesColor::HasColors()) { + set_field_fore(this->Field, A_NORMAL); + set_field_back(this->Field, A_STANDOUT); + } + field_opts_off(this->Field, O_STATIC); + this->SetValueAsBool(false); +} + +bool cmCursesBoolWidget::HandleInput(int& key, cmCursesMainForm* /*fm*/, + WINDOW* w) +{ + + // toggle boolean values with enter or space + // 10 == enter + if (key == 10 || key == KEY_ENTER || key == ' ') { + if (this->GetValueAsBool()) { + this->SetValueAsBool(false); + } else { + this->SetValueAsBool(true); + } + + touchwin(w); + wrefresh(w); + return true; + } + return false; +} + +void cmCursesBoolWidget::SetValueAsBool(bool value) +{ + if (value) { + this->SetValue("ON"); + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOn)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOn)); + } + } else { + this->SetValue("OFF"); + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOff)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOff)); + } + } +} + +bool cmCursesBoolWidget::GetValueAsBool() +{ + return this->Value == "ON"; +} diff --git a/Source/CursesDialog/cmCursesBoolWidget.h b/Source/CursesDialog/cmCursesBoolWidget.h new file mode 100644 index 0000000..8c96256 --- /dev/null +++ b/Source/CursesDialog/cmCursesBoolWidget.h @@ -0,0 +1,33 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesBoolWidget_h +#define cmCursesBoolWidget_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmCursesStandardIncludes.h" +#include "cmCursesWidget.h" + +class cmCursesMainForm; + +class cmCursesBoolWidget : public cmCursesWidget +{ +public: + cmCursesBoolWidget(int width, int height, int left, int top); + + cmCursesBoolWidget(cmCursesBoolWidget const&) = delete; + cmCursesBoolWidget& operator=(cmCursesBoolWidget const&) = delete; + + // Description: + // Handle user input. Called by the container of this widget + // when this widget has focus. Returns true if the input was + // handled. + bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override; + + // Description: + // Set/Get the value (on/off). + void SetValueAsBool(bool value); + bool GetValueAsBool(); +}; + +#endif // cmCursesBoolWidget_h diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx new file mode 100644 index 0000000..9250fbc --- /dev/null +++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx @@ -0,0 +1,108 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesCacheEntryComposite.h" + +#include <cassert> +#include <utility> +#include <vector> + +#include <cm/memory> + +#include "cmCursesBoolWidget.h" +#include "cmCursesFilePathWidget.h" +#include "cmCursesLabelWidget.h" +#include "cmCursesOptionsWidget.h" +#include "cmCursesPathWidget.h" +#include "cmCursesStringWidget.h" +#include "cmCursesWidget.h" +#include "cmState.h" +#include "cmStateTypes.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +cmCursesCacheEntryComposite::cmCursesCacheEntryComposite( + const std::string& key, int labelwidth, int entrywidth) + : Key(key) + , LabelWidth(labelwidth) + , EntryWidth(entrywidth) +{ + this->Label = + cm::make_unique<cmCursesLabelWidget>(this->LabelWidth, 1, 1, 1, key); + this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, " "); + this->Entry = + cm::make_unique<cmCursesStringWidget>(this->EntryWidth, 1, 1, 1); +} + +cmCursesCacheEntryComposite::cmCursesCacheEntryComposite( + const std::string& key, cmState* state, bool isNew, int labelwidth, + int entrywidth) + : Key(key) + , LabelWidth(labelwidth) + , EntryWidth(entrywidth) +{ + this->Label = + cm::make_unique<cmCursesLabelWidget>(this->LabelWidth, 1, 1, 1, key); + if (isNew) { + this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, "*"); + } else { + this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, " "); + } + + cmProp value = state->GetCacheEntryValue(key); + assert(value); + switch (state->GetCacheEntryType(key)) { + case cmStateEnums::BOOL: { + auto bw = cm::make_unique<cmCursesBoolWidget>(this->EntryWidth, 1, 1, 1); + bw->SetValueAsBool(cmIsOn(*value)); + this->Entry = std::move(bw); + break; + } + case cmStateEnums::PATH: { + auto pw = cm::make_unique<cmCursesPathWidget>(this->EntryWidth, 1, 1, 1); + pw->SetString(*value); + this->Entry = std::move(pw); + break; + } + case cmStateEnums::FILEPATH: { + auto fpw = + cm::make_unique<cmCursesFilePathWidget>(this->EntryWidth, 1, 1, 1); + fpw->SetString(*value); + this->Entry = std::move(fpw); + break; + } + case cmStateEnums::STRING: { + cmProp stringsProp = state->GetCacheEntryProperty(key, "STRINGS"); + if (stringsProp) { + auto ow = + cm::make_unique<cmCursesOptionsWidget>(this->EntryWidth, 1, 1, 1); + for (std::string const& opt : cmExpandedList(*stringsProp)) { + ow->AddOption(opt); + } + ow->SetOption(*value); + this->Entry = std::move(ow); + } else { + auto sw = + cm::make_unique<cmCursesStringWidget>(this->EntryWidth, 1, 1, 1); + sw->SetString(*value); + this->Entry = std::move(sw); + } + break; + } + case cmStateEnums::UNINITIALIZED: + cmSystemTools::Error("Found an undefined variable: " + key); + break; + default: + // TODO : put warning message here + break; + } +} + +cmCursesCacheEntryComposite::~cmCursesCacheEntryComposite() = default; + +const char* cmCursesCacheEntryComposite::GetValue() +{ + if (this->Label) { + return this->Label->GetValue(); + } + return nullptr; +} diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.h b/Source/CursesDialog/cmCursesCacheEntryComposite.h new file mode 100644 index 0000000..a711363 --- /dev/null +++ b/Source/CursesDialog/cmCursesCacheEntryComposite.h @@ -0,0 +1,45 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesCacheEntryComposite_h +#define cmCursesCacheEntryComposite_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <memory> +#include <string> + +class cmCursesLabelWidget; +class cmCursesWidget; +class cmState; + +class cmCursesCacheEntryComposite +{ +public: + cmCursesCacheEntryComposite(const std::string& key, int labelwidth, + int entrywidth); + cmCursesCacheEntryComposite(const std::string& key, cmState* state, + bool isNew, int labelwidth, int entrywidth); + ~cmCursesCacheEntryComposite(); + + cmCursesCacheEntryComposite(cmCursesCacheEntryComposite const&) = delete; + cmCursesCacheEntryComposite& operator=(cmCursesCacheEntryComposite const&) = + delete; + + cmCursesCacheEntryComposite(cmCursesCacheEntryComposite&&) = default; + cmCursesCacheEntryComposite& operator=(cmCursesCacheEntryComposite&&) = + default; + + const char* GetValue(); + + friend class cmCursesMainForm; + +protected: + std::unique_ptr<cmCursesLabelWidget> Label; + std::unique_ptr<cmCursesLabelWidget> IsNewLabel; + std::unique_ptr<cmCursesWidget> Entry; + std::string Key; + int LabelWidth; + int EntryWidth; +}; + +#endif // cmCursesCacheEntryComposite_h diff --git a/Source/CursesDialog/cmCursesColor.cxx b/Source/CursesDialog/cmCursesColor.cxx new file mode 100644 index 0000000..641d48c --- /dev/null +++ b/Source/CursesDialog/cmCursesColor.cxx @@ -0,0 +1,29 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesColor.h" + +#include "cmCursesStandardIncludes.h" + +bool cmCursesColor::HasColors() +{ +#ifdef HAVE_CURSES_USE_DEFAULT_COLORS + return has_colors(); +#else + return false; +#endif +} + +void cmCursesColor::InitColors() +{ +#ifdef HAVE_CURSES_USE_DEFAULT_COLORS + if (HasColors()) { + start_color(); + use_default_colors(); + init_pair(cmCursesColor::BoolOff, COLOR_RED, -1); + init_pair(cmCursesColor::BoolOn, COLOR_GREEN, -1); + init_pair(cmCursesColor::String, COLOR_BLUE, -1); + init_pair(cmCursesColor::Path, COLOR_YELLOW, -1); + init_pair(cmCursesColor::Options, COLOR_MAGENTA, -1); + } +#endif +} diff --git a/Source/CursesDialog/cmCursesColor.h b/Source/CursesDialog/cmCursesColor.h new file mode 100644 index 0000000..78ca52c --- /dev/null +++ b/Source/CursesDialog/cmCursesColor.h @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesColor_h +#define cmCursesColor_h + +class cmCursesColor +{ +public: + enum Color + { + // Default color is pair 0 + BoolOff = 1, + BoolOn, + String, + Path, + Options + }; + + static bool HasColors(); + + static void InitColors(); +}; + +#endif // cmCursesColor_h diff --git a/Source/CursesDialog/cmCursesDummyWidget.cxx b/Source/CursesDialog/cmCursesDummyWidget.cxx new file mode 100644 index 0000000..da0478a --- /dev/null +++ b/Source/CursesDialog/cmCursesDummyWidget.cxx @@ -0,0 +1,19 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesDummyWidget.h" + +#include "cmCursesWidget.h" +#include "cmStateTypes.h" + +cmCursesDummyWidget::cmCursesDummyWidget(int width, int height, int left, + int top) + : cmCursesWidget(width, height, left, top) +{ + this->Type = cmStateEnums::INTERNAL; +} + +bool cmCursesDummyWidget::HandleInput(int& /*key*/, cmCursesMainForm* /*fm*/, + WINDOW* /*w*/) +{ + return false; +} diff --git a/Source/CursesDialog/cmCursesDummyWidget.h b/Source/CursesDialog/cmCursesDummyWidget.h new file mode 100644 index 0000000..07b7288 --- /dev/null +++ b/Source/CursesDialog/cmCursesDummyWidget.h @@ -0,0 +1,28 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesDummyWidget_h +#define cmCursesDummyWidget_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmCursesStandardIncludes.h" +#include "cmCursesWidget.h" + +class cmCursesMainForm; + +class cmCursesDummyWidget : public cmCursesWidget +{ +public: + cmCursesDummyWidget(int width, int height, int left, int top); + + cmCursesDummyWidget(cmCursesDummyWidget const&) = delete; + cmCursesDummyWidget& operator=(cmCursesDummyWidget const&) = delete; + + // Description: + // Handle user input. Called by the container of this widget + // when this widget has focus. Returns true if the input was + // handled. + bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override; +}; + +#endif // cmCursesDummyWidget_h diff --git a/Source/CursesDialog/cmCursesFilePathWidget.cxx b/Source/CursesDialog/cmCursesFilePathWidget.cxx new file mode 100644 index 0000000..518da4f --- /dev/null +++ b/Source/CursesDialog/cmCursesFilePathWidget.cxx @@ -0,0 +1,13 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesFilePathWidget.h" + +#include "cmCursesPathWidget.h" +#include "cmStateTypes.h" + +cmCursesFilePathWidget::cmCursesFilePathWidget(int width, int height, int left, + int top) + : cmCursesPathWidget(width, height, left, top) +{ + this->Type = cmStateEnums::FILEPATH; +} diff --git a/Source/CursesDialog/cmCursesFilePathWidget.h b/Source/CursesDialog/cmCursesFilePathWidget.h new file mode 100644 index 0000000..3f71259 --- /dev/null +++ b/Source/CursesDialog/cmCursesFilePathWidget.h @@ -0,0 +1,19 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesFilePathWidget_h +#define cmCursesFilePathWidget_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmCursesPathWidget.h" + +class cmCursesFilePathWidget : public cmCursesPathWidget +{ +public: + cmCursesFilePathWidget(int width, int height, int left, int top); + + cmCursesFilePathWidget(cmCursesFilePathWidget const&) = delete; + cmCursesFilePathWidget& operator=(cmCursesFilePathWidget const&) = delete; +}; + +#endif // cmCursesFilePathWidget_h diff --git a/Source/CursesDialog/cmCursesForm.cxx b/Source/CursesDialog/cmCursesForm.cxx new file mode 100644 index 0000000..bd65c4a --- /dev/null +++ b/Source/CursesDialog/cmCursesForm.cxx @@ -0,0 +1,45 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesForm.h" + +cmsys::ofstream cmCursesForm::DebugFile; +bool cmCursesForm::Debug = false; + +cmCursesForm::cmCursesForm() +{ + this->Form = nullptr; +} + +cmCursesForm::~cmCursesForm() +{ + if (this->Form) { + unpost_form(this->Form); + free_form(this->Form); + this->Form = nullptr; + } +} + +void cmCursesForm::DebugStart() +{ + cmCursesForm::Debug = true; + cmCursesForm::DebugFile.open("ccmakelog.txt"); +} + +void cmCursesForm::DebugEnd() +{ + if (!cmCursesForm::Debug) { + return; + } + + cmCursesForm::Debug = false; + cmCursesForm::DebugFile.close(); +} + +void cmCursesForm::LogMessage(const char* msg) +{ + if (!cmCursesForm::Debug) { + return; + } + + cmCursesForm::DebugFile << msg << std::endl; +} diff --git a/Source/CursesDialog/cmCursesForm.h b/Source/CursesDialog/cmCursesForm.h new file mode 100644 index 0000000..e3626e6 --- /dev/null +++ b/Source/CursesDialog/cmCursesForm.h @@ -0,0 +1,66 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesForm_h +#define cmCursesForm_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> + +#include "cmsys/FStream.hxx" + +#include "cmCursesStandardIncludes.h" + +class cmCursesForm +{ +public: + cmCursesForm(); + virtual ~cmCursesForm(); + + cmCursesForm(cmCursesForm const&) = delete; + cmCursesForm& operator=(cmCursesForm const&) = delete; + + // Description: + // Handle user input. + virtual void HandleInput() = 0; + + // Description: + // Display form. + virtual void Render(int left, int top, int width, int height) = 0; + + // Description: + // This method should normally called only by the form. + // The only exception is during a resize. + virtual void UpdateStatusBar() = 0; + + // Description: + // During a CMake run, an error handle should add errors + // to be displayed afterwards. + virtual void AddError(const std::string&, const char*) {} + + // Description: + // Turn debugging on. This will create ccmakelog.txt. + static void DebugStart(); + + // Description: + // Turn debugging off. This will close ccmakelog.txt. + static void DebugEnd(); + + // Description: + // Write a debugging message. + static void LogMessage(const char* msg); + + // Description: + // Return the FORM. Should be only used by low-level methods. + FORM* GetForm() { return this->Form; } + + static cmCursesForm* CurrentForm; + +protected: + static cmsys::ofstream DebugFile; + static bool Debug; + + FORM* Form; +}; + +#endif // cmCursesForm_h diff --git a/Source/CursesDialog/cmCursesLabelWidget.cxx b/Source/CursesDialog/cmCursesLabelWidget.cxx new file mode 100644 index 0000000..83aea5a --- /dev/null +++ b/Source/CursesDialog/cmCursesLabelWidget.cxx @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesLabelWidget.h" + +#include "cmCursesWidget.h" + +cmCursesLabelWidget::cmCursesLabelWidget(int width, int height, int left, + int top, const std::string& name) + : cmCursesWidget(width, height, left, top) +{ + field_opts_off(this->Field, O_EDIT); + field_opts_off(this->Field, O_ACTIVE); + field_opts_off(this->Field, O_STATIC); + this->SetValue(name); +} + +cmCursesLabelWidget::~cmCursesLabelWidget() = default; + +bool cmCursesLabelWidget::HandleInput(int& /*key*/, cmCursesMainForm* /*fm*/, + WINDOW* /*w*/) +{ + // Static text. No input is handled here. + return false; +} diff --git a/Source/CursesDialog/cmCursesLabelWidget.h b/Source/CursesDialog/cmCursesLabelWidget.h new file mode 100644 index 0000000..9e75681 --- /dev/null +++ b/Source/CursesDialog/cmCursesLabelWidget.h @@ -0,0 +1,32 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesLabelWidget_h +#define cmCursesLabelWidget_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> + +#include "cmCursesStandardIncludes.h" +#include "cmCursesWidget.h" + +class cmCursesMainForm; + +class cmCursesLabelWidget : public cmCursesWidget +{ +public: + cmCursesLabelWidget(int width, int height, int left, int top, + const std::string& name); + ~cmCursesLabelWidget() override; + + cmCursesLabelWidget(cmCursesLabelWidget const&) = delete; + cmCursesLabelWidget& operator=(cmCursesLabelWidget const&) = delete; + + // Description: + // Handle user input. Called by the container of this widget + // when this widget has focus. Returns true if the input was + // handled + bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override; +}; + +#endif // cmCursesLabelWidget_h diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx new file mode 100644 index 0000000..664ba2f --- /dev/null +++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx @@ -0,0 +1,200 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesLongMessageForm.h" + +#include <cstdio> +#include <cstring> + +#include "cmCursesForm.h" +#include "cmCursesMainForm.h" +#include "cmCursesStandardIncludes.h" +#include "cmStringAlgorithms.h" +#include "cmVersion.h" + +inline int ctrl(int z) +{ + return (z & 037); +} + +cmCursesLongMessageForm::cmCursesLongMessageForm( + std::vector<std::string> const& messages, const char* title, + ScrollBehavior scrollBehavior) + : Scrolling(scrollBehavior) +{ + // Append all messages into on big string + this->Messages = cmJoin(messages, "\n"); + this->Title = title; + this->Fields[0] = nullptr; + this->Fields[1] = nullptr; +} + +cmCursesLongMessageForm::~cmCursesLongMessageForm() +{ + if (this->Fields[0]) { + free_field(this->Fields[0]); + } +} + +void cmCursesLongMessageForm::UpdateContent(std::string const& output, + std::string const& title) +{ + this->Title = title; + + if (!output.empty() && this->Messages.size() < MAX_CONTENT_SIZE) { + this->Messages.push_back('\n'); + this->Messages.append(output); + form_driver(this->Form, REQ_NEW_LINE); + this->DrawMessage(output.c_str()); + } + + this->UpdateStatusBar(); + touchwin(stdscr); + refresh(); +} + +void cmCursesLongMessageForm::UpdateStatusBar() +{ + int x; + int y; + getmaxyx(stdscr, y, x); + + char bar[cmCursesMainForm::MAX_WIDTH]; + size_t size = this->Title.size(); + if (size >= cmCursesMainForm::MAX_WIDTH) { + size = cmCursesMainForm::MAX_WIDTH - 1; + } + strncpy(bar, this->Title.c_str(), size); + for (size_t i = size; i < cmCursesMainForm::MAX_WIDTH; i++) { + bar[i] = ' '; + } + int width; + if (x < cmCursesMainForm::MAX_WIDTH) { + width = x; + } else { + width = cmCursesMainForm::MAX_WIDTH - 1; + } + + bar[width] = '\0'; + + char version[cmCursesMainForm::MAX_WIDTH]; + char vertmp[128]; + sprintf(vertmp, "CMake Version %s", cmVersion::GetCMakeVersion()); + size_t sideSpace = (width - strlen(vertmp)); + for (size_t i = 0; i < sideSpace; i++) { + version[i] = ' '; + } + sprintf(version + sideSpace, "%s", vertmp); + version[width] = '\0'; + + char fmt_s[] = "%s"; + curses_move(y - 4, 0); + attron(A_STANDOUT); + printw(fmt_s, bar); + attroff(A_STANDOUT); + curses_move(y - 3, 0); + printw(fmt_s, version); + pos_form_cursor(this->Form); +} + +void cmCursesLongMessageForm::PrintKeys() +{ + int x; + int y; + getmaxyx(stdscr, y, x); + if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) { + return; + } + char firstLine[512]; + sprintf(firstLine, "Press [e] to exit screen"); + + char fmt_s[] = "%s"; + curses_move(y - 2, 0); + printw(fmt_s, firstLine); + pos_form_cursor(this->Form); +} + +void cmCursesLongMessageForm::Render(int /*left*/, int /*top*/, int /*width*/, + int /*height*/) +{ + int x; + int y; + getmaxyx(stdscr, y, x); + + if (this->Form) { + unpost_form(this->Form); + free_form(this->Form); + this->Form = nullptr; + } + + if (this->Fields[0]) { + free_field(this->Fields[0]); + this->Fields[0] = nullptr; + } + + this->Fields[0] = new_field(y - 6, x - 2, 1, 1, 0, 0); + + field_opts_off(this->Fields[0], O_STATIC); + + this->Form = new_form(this->Fields); + post_form(this->Form); + + form_driver(this->Form, REQ_BEG_FIELD); + this->DrawMessage(this->Messages.c_str()); + + this->UpdateStatusBar(); + touchwin(stdscr); + refresh(); +} + +void cmCursesLongMessageForm::DrawMessage(const char* msg) const +{ + int i = 0; + while (msg[i] != '\0' && i < MAX_CONTENT_SIZE) { + if (msg[i] == '\n' && msg[i + 1] != '\0') { + form_driver(this->Form, REQ_NEW_LINE); + } else { + form_driver(this->Form, msg[i]); + } + i++; + } + if (this->Scrolling == ScrollBehavior::ScrollDown) { + form_driver(this->Form, REQ_END_FIELD); + } else { + form_driver(this->Form, REQ_BEG_FIELD); + } +} + +void cmCursesLongMessageForm::HandleInput() +{ + if (!this->Form) { + return; + } + + char debugMessage[128]; + + for (;;) { + this->PrintKeys(); + int key = getch(); + + sprintf(debugMessage, "Message widget handling input, key: %d", key); + cmCursesForm::LogMessage(debugMessage); + + // quit + if (key == 'o' || key == 'e') { + break; + } + if (key == KEY_DOWN || key == ctrl('n')) { + form_driver(this->Form, REQ_SCR_FLINE); + } else if (key == KEY_UP || key == ctrl('p')) { + form_driver(this->Form, REQ_SCR_BLINE); + } else if (key == KEY_NPAGE || key == ctrl('d')) { + form_driver(this->Form, REQ_SCR_FPAGE); + } else if (key == KEY_PPAGE || key == ctrl('u')) { + form_driver(this->Form, REQ_SCR_BPAGE); + } + + this->UpdateStatusBar(); + touchwin(stdscr); + wrefresh(stdscr); + } +} diff --git a/Source/CursesDialog/cmCursesLongMessageForm.h b/Source/CursesDialog/cmCursesLongMessageForm.h new file mode 100644 index 0000000..da9fea2 --- /dev/null +++ b/Source/CursesDialog/cmCursesLongMessageForm.h @@ -0,0 +1,63 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesLongMessageForm_h +#define cmCursesLongMessageForm_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> +#include <vector> + +#include "cmCursesForm.h" +#include "cmCursesStandardIncludes.h" + +class cmCursesLongMessageForm : public cmCursesForm +{ +public: + enum class ScrollBehavior + { + NoScroll, + ScrollDown + }; + + cmCursesLongMessageForm(std::vector<std::string> const& messages, + const char* title, ScrollBehavior scrollBehavior); + ~cmCursesLongMessageForm() override; + + cmCursesLongMessageForm(cmCursesLongMessageForm const&) = delete; + cmCursesLongMessageForm& operator=(cmCursesLongMessageForm const&) = delete; + + void UpdateContent(std::string const& output, std::string const& title); + + // Description: + // Handle user input. + void HandleInput() override; + + // Description: + // Display form. Use a window of size width x height, starting + // at top, left. + void Render(int left, int top, int width, int height) override; + + // Description: + // This method should normally called only by the form. + // The only exception is during a resize. + void PrintKeys(); + + // Description: + // This method should normally called only by the form. + // The only exception is during a resize. + void UpdateStatusBar() override; + +protected: + static constexpr int MAX_CONTENT_SIZE = 60000; + + void DrawMessage(const char* msg) const; + + std::string Messages; + std::string Title; + ScrollBehavior Scrolling; + + FIELD* Fields[2]; +}; + +#endif // cmCursesLongMessageForm_h diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx new file mode 100644 index 0000000..df34283 --- /dev/null +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -0,0 +1,1078 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesMainForm.h" + +#include <algorithm> +#include <cstdio> +#include <cstring> +#include <utility> + +#include <cm/memory> + +#include "cmCursesCacheEntryComposite.h" +#include "cmCursesDummyWidget.h" +#include "cmCursesForm.h" +#include "cmCursesLabelWidget.h" +#include "cmCursesLongMessageForm.h" +#include "cmCursesStandardIncludes.h" +#include "cmCursesStringWidget.h" +#include "cmCursesWidget.h" +#include "cmState.h" +#include "cmStateTypes.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmVersion.h" +#include "cmake.h" + +inline int ctrl(int z) +{ + return (z & 037); +} + +cmCursesMainForm::cmCursesMainForm(std::vector<std::string> args, + int initWidth) + : Args(std::move(args)) + , InitialWidth(initWidth) +{ + this->HasNonStatusOutputs = false; + this->NumberOfPages = 0; + this->AdvancedMode = false; + this->NumberOfVisibleEntries = 0; + this->OkToGenerate = false; + this->HelpMessage.emplace_back( + "Welcome to ccmake, curses based user interface for CMake."); + this->HelpMessage.emplace_back(); + this->HelpMessage.emplace_back(s_ConstHelpMessage); + this->CMakeInstance = + cm::make_unique<cmake>(cmake::RoleProject, cmState::Project); + this->CMakeInstance->SetCMakeEditCommand( + cmSystemTools::GetCMakeCursesCommand()); + + // create the arguments for the cmake object + std::string whereCMake = + cmStrCat(cmSystemTools::GetProgramPath(this->Args[0]), "/cmake"); + this->Args[0] = whereCMake; + this->CMakeInstance->SetArgs(this->Args); + this->SearchMode = false; +} + +cmCursesMainForm::~cmCursesMainForm() +{ + if (this->Form) { + unpost_form(this->Form); + free_form(this->Form); + this->Form = nullptr; + } +} + +// See if a cache entry is in the list of entries in the ui. +bool cmCursesMainForm::LookForCacheEntry(const std::string& key) +{ + return std::any_of(this->Entries.begin(), this->Entries.end(), + [&key](cmCursesCacheEntryComposite const& entry) { + return key == entry.Key; + }); +} + +// Create new cmCursesCacheEntryComposite entries from the cache +void cmCursesMainForm::InitializeUI() +{ + // Create a vector of cmCursesCacheEntryComposite's + // which contain labels, entries and new entry markers + std::vector<cmCursesCacheEntryComposite> newEntries; + std::vector<std::string> cacheKeys = + this->CMakeInstance->GetState()->GetCacheEntryKeys(); + newEntries.reserve(cacheKeys.size()); + + // Count non-internal and non-static entries + int count = 0; + + for (std::string const& key : cacheKeys) { + cmStateEnums::CacheEntryType t = + this->CMakeInstance->GetState()->GetCacheEntryType(key); + if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC && + t != cmStateEnums::UNINITIALIZED) { + ++count; + } + } + + int entrywidth = this->InitialWidth - 35; + + if (count == 0) { + // If cache is empty, display a label saying so and a + // dummy entry widget (does not respond to input) + cmCursesCacheEntryComposite comp("EMPTY CACHE", 30, 30); + comp.Entry = cm::make_unique<cmCursesDummyWidget>(1, 1, 1, 1); + newEntries.emplace_back(std::move(comp)); + } else { + // Create the composites. + + // First add entries which are new + for (std::string const& key : cacheKeys) { + cmStateEnums::CacheEntryType t = + this->CMakeInstance->GetState()->GetCacheEntryType(key); + if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC || + t == cmStateEnums::UNINITIALIZED) { + continue; + } + + if (!this->LookForCacheEntry(key)) { + newEntries.emplace_back(key, this->CMakeInstance->GetState(), true, 30, + entrywidth); + this->OkToGenerate = false; + } + } + + // then add entries which are old + for (std::string const& key : cacheKeys) { + cmStateEnums::CacheEntryType t = + this->CMakeInstance->GetState()->GetCacheEntryType(key); + if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC || + t == cmStateEnums::UNINITIALIZED) { + continue; + } + + if (this->LookForCacheEntry(key)) { + newEntries.emplace_back(key, this->CMakeInstance->GetState(), false, + 30, entrywidth); + } + } + } + + // Replace old entries + this->Entries = std::move(newEntries); + + // Compute fields from composites + this->RePost(); +} + +void cmCursesMainForm::RePost() +{ + // Create the fields to be passed to the form. + if (this->Form) { + unpost_form(this->Form); + free_form(this->Form); + this->Form = nullptr; + } + this->Fields.clear(); + if (this->AdvancedMode) { + this->NumberOfVisibleEntries = this->Entries.size(); + } else { + // If normal mode, count only non-advanced entries + this->NumberOfVisibleEntries = 0; + for (cmCursesCacheEntryComposite& entry : this->Entries) { + cmProp existingValue = + this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); + bool advanced = + this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( + entry.GetValue(), "ADVANCED"); + if (!existingValue || (!this->AdvancedMode && advanced)) { + continue; + } + this->NumberOfVisibleEntries++; + } + } + // there is always one even if it is the dummy one + if (this->NumberOfVisibleEntries == 0) { + this->NumberOfVisibleEntries = 1; + } + // Assign the fields: 3 for each entry: label, new entry marker + // ('*' or ' ') and entry widget + this->Fields.reserve(3 * this->NumberOfVisibleEntries + 1); + + // Assign fields + for (cmCursesCacheEntryComposite& entry : this->Entries) { + cmProp existingValue = + this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); + bool advanced = + this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( + entry.GetValue(), "ADVANCED"); + if (!existingValue || (!this->AdvancedMode && advanced)) { + continue; + } + this->Fields.push_back(entry.Label->Field); + this->Fields.push_back(entry.IsNewLabel->Field); + this->Fields.push_back(entry.Entry->Field); + } + // if no cache entries there should still be one dummy field + if (this->Fields.empty()) { + const auto& front = this->Entries.front(); + this->Fields.push_back(front.Label->Field); + this->Fields.push_back(front.IsNewLabel->Field); + this->Fields.push_back(front.Entry->Field); + this->NumberOfVisibleEntries = 1; + } + // Has to be null terminated. + this->Fields.push_back(nullptr); +} + +void cmCursesMainForm::Render(int left, int top, int width, int height) +{ + + if (this->Form) { + FIELD* currentField = current_field(this->Form); + cmCursesWidget* cw = + reinterpret_cast<cmCursesWidget*>(field_userptr(currentField)); + // If in edit mode, get out of it + if (cw->GetType() == cmStateEnums::STRING || + cw->GetType() == cmStateEnums::PATH || + cw->GetType() == cmStateEnums::FILEPATH) { + cmCursesStringWidget* sw = static_cast<cmCursesStringWidget*>(cw); + sw->SetInEdit(false); + } + // Delete the previous form + unpost_form(this->Form); + free_form(this->Form); + this->Form = nullptr; + } + + // Wrong window size + if (width < cmCursesMainForm::MIN_WIDTH || width < this->InitialWidth || + height < cmCursesMainForm::MIN_HEIGHT) { + return; + } + + // Leave room for toolbar + height -= 7; + + if (this->AdvancedMode) { + this->NumberOfVisibleEntries = this->Entries.size(); + } else { + // If normal, display only non-advanced entries + this->NumberOfVisibleEntries = 0; + for (cmCursesCacheEntryComposite& entry : this->Entries) { + cmProp existingValue = + this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); + bool advanced = + this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( + entry.GetValue(), "ADVANCED"); + if (!existingValue || (!this->AdvancedMode && advanced)) { + continue; + } + this->NumberOfVisibleEntries++; + } + } + + // Re-adjust the fields according to their place + this->NumberOfPages = 1; + if (height > 0) { + bool isNewPage; + int i = 0; + for (cmCursesCacheEntryComposite& entry : this->Entries) { + cmProp existingValue = + this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); + bool advanced = + this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( + entry.GetValue(), "ADVANCED"); + if (!existingValue || (!this->AdvancedMode && advanced)) { + continue; + } + int row = (i % height) + 1; + int page = (i / height) + 1; + isNewPage = (page > 1) && (row == 1); + + if (isNewPage) { + this->NumberOfPages++; + } + entry.Label->Move(left, top + row - 1, isNewPage); + entry.IsNewLabel->Move(left + 32, top + row - 1, false); + entry.Entry->Move(left + 33, top + row - 1, false); + entry.Entry->SetPage(this->NumberOfPages); + i++; + } + } + + // Post the form + this->Form = new_form(this->Fields.data()); + post_form(this->Form); + // Update toolbar + this->UpdateStatusBar(); + this->PrintKeys(); + + touchwin(stdscr); + refresh(); +} + +void cmCursesMainForm::PrintKeys(int process /* = 0 */) +{ + int x; + int y; + getmaxyx(stdscr, y, x); + if (x < cmCursesMainForm::MIN_WIDTH || x < this->InitialWidth || + y < cmCursesMainForm::MIN_HEIGHT) { + return; + } + + // Give the current widget (if it exists), a chance to print keys + cmCursesWidget* cw = nullptr; + if (this->Form) { + FIELD* currentField = current_field(this->Form); + cw = reinterpret_cast<cmCursesWidget*>(field_userptr(currentField)); + } + + char fmt_s[] = "%s"; + if (cw == nullptr || !cw->PrintKeys()) { + char firstLine[512] = ""; + char secondLine[512] = ""; + char thirdLine[512] = ""; + if (process) { + memset(firstLine, ' ', 68); + memset(secondLine, ' ', 68); + memset(thirdLine, ' ', 68); + } else { + if (this->OkToGenerate) { + sprintf(firstLine, + " [l] Show log output [c] Configure" + " [g] Generate "); + } else { + sprintf(firstLine, + " [l] Show log output [c] Configure" + " "); + } + { + const char* toggleKeyInstruction = + " [t] Toggle advanced mode (currently %s)"; + sprintf(thirdLine, toggleKeyInstruction, + this->AdvancedMode ? "on" : "off"); + } + sprintf(secondLine, + " [h] Help [q] Quit without generating"); + } + + curses_move(y - 4, 0); + char fmt[512] = "Keys: [enter] Edit an entry [d] Delete an entry"; + if (process) { + memset(fmt, ' ', 57); + } + printw(fmt_s, fmt); + curses_move(y - 3, 0); + printw(fmt_s, firstLine); + curses_move(y - 2, 0); + printw(fmt_s, secondLine); + curses_move(y - 1, 0); + printw(fmt_s, thirdLine); + } + + if (cw) { + char pageLine[512] = ""; + sprintf(pageLine, "Page %d of %d", cw->GetPage(), this->NumberOfPages); + curses_move(0, 65 - static_cast<unsigned int>(strlen(pageLine)) - 1); + printw(fmt_s, pageLine); + } + + pos_form_cursor(this->Form); +} + +// Print the key of the current entry and the CMake version +// on the status bar. Designed for a width of 80 chars. +void cmCursesMainForm::UpdateStatusBar(cm::optional<std::string> message) +{ + int x; + int y; + getmaxyx(stdscr, y, x); + // If window size is too small, display error and return + if (x < cmCursesMainForm::MIN_WIDTH || x < this->InitialWidth || + y < cmCursesMainForm::MIN_HEIGHT) { + curses_clear(); + curses_move(0, 0); + char fmt[] = "Window is too small. A size of at least %dx%d is required."; + printw(fmt, + (cmCursesMainForm::MIN_WIDTH < this->InitialWidth + ? this->InitialWidth + : cmCursesMainForm::MIN_WIDTH), + cmCursesMainForm::MIN_HEIGHT); + touchwin(stdscr); + wrefresh(stdscr); + return; + } + + // Find the current label index + // Field are grouped by 3, the label should be 2 less than the current index + using size_type = decltype(this->Fields)::size_type; + size_type currentLabelIndex = field_index(current_field(this->Form)) - 2; + + // Use the status message if any, otherwise join the key and help string + std::string bar; + if (message) { + bar = *message; + } else { + // Get the key of the current entry + cmCursesWidget* labelWidget = reinterpret_cast<cmCursesWidget*>( + field_userptr(this->Fields[currentLabelIndex])); + std::string labelValue = labelWidget->GetValue(); + bar = labelValue + ": "; + + // Get the help string of the current entry + // and add it to the help string + auto cmakeState = this->CMakeInstance->GetState(); + cmProp existingValue = cmakeState->GetCacheEntryValue(labelValue); + if (existingValue) { + cmProp help = + cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING"); + if (help) { + bar += *help; + } + } + } + // Pad with spaces to erase any previous text, + // or truncate as necessary to fit the screen + bar.resize(x, ' '); + curses_move(y - 5, 0); + attron(A_STANDOUT); + char fmt_s[] = "%s"; + printw(fmt_s, bar.c_str()); + attroff(A_STANDOUT); + + // Highlight the current label, reset others + // Fields are grouped by 3, the first one being the label + // so start at 0 and move up by 3 avoiding the last null entry + for (size_type index = 0; index < this->Fields.size() - 1; index += 3) { + bool currentLabel = index == currentLabelIndex; + set_field_fore(this->Fields[index], currentLabel ? A_STANDOUT : A_NORMAL); + } + + // Display CMake version under the status bar + // We want to display this on the right + std::string version = "CMake Version "; + version += cmVersion::GetCMakeVersion(); + version.resize(std::min<std::string::size_type>(x, version.size())); + curses_move(y - 4, x - static_cast<int>(version.size())); + printw(fmt_s, version.c_str()); + + pos_form_cursor(this->Form); +} + +void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog) +{ + if (prog >= 0) { + constexpr int progressBarWidth = 40; + int progressBarCompleted = static_cast<int>(progressBarWidth * prog); + int percentCompleted = static_cast<int>(100 * prog); + this->LastProgress = (percentCompleted < 100 ? " " : ""); + this->LastProgress += (percentCompleted < 10 ? " " : ""); + this->LastProgress += std::to_string(percentCompleted) + "% ["; + this->LastProgress.append(progressBarCompleted, '#'); + this->LastProgress.append(progressBarWidth - progressBarCompleted, ' '); + this->LastProgress += "] " + msg + "..."; + this->DisplayOutputs(std::string()); + } else { + this->Outputs.emplace_back(msg); + this->DisplayOutputs(msg); + } +} + +int cmCursesMainForm::Configure(int noconfigure) +{ + this->ResetOutputs(); + + if (noconfigure == 0) { + this->UpdateProgress("Configuring", 0); + this->CMakeInstance->SetProgressCallback( + [this](const std::string& msg, float prog) { + this->UpdateProgress(msg, prog); + }); + } + + // always save the current gui values to disk + this->FillCacheManagerFromUI(); + this->CMakeInstance->SaveCache( + this->CMakeInstance->GetHomeOutputDirectory()); + this->LoadCache(nullptr); + + // run the generate process + this->OkToGenerate = true; + int retVal; + if (noconfigure) { + retVal = this->CMakeInstance->DoPreConfigureChecks(); + this->OkToGenerate = false; + if (retVal > 0) { + retVal = 0; + } + } else { + retVal = this->CMakeInstance->Configure(); + } + this->CMakeInstance->SetProgressCallback(nullptr); + + keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ + + if (retVal != 0 || this->HasNonStatusOutputs) { + // see if there was an error + if (cmSystemTools::GetErrorOccuredFlag()) { + this->OkToGenerate = false; + } + int xx; + int yy; + getmaxyx(stdscr, yy, xx); + const char* title = "Configure produced the following output"; + if (cmSystemTools::GetErrorOccuredFlag()) { + title = "Configure failed with the following output"; + } + cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm( + this->Outputs, title, + cmCursesLongMessageForm::ScrollBehavior::ScrollDown); + // reset error condition + cmSystemTools::ResetErrorOccuredFlag(); + CurrentForm = msgs; + msgs->Render(1, 1, xx, yy); + msgs->HandleInput(); + // If they typed the wrong source directory, we report + // an error and exit + if (retVal == -2) { + return retVal; + } + } + + this->InitializeUI(); + CurrentForm = this; + int xi; + int yi; + getmaxyx(stdscr, yi, xi); + this->Render(1, 1, xi, yi); + + return 0; +} + +int cmCursesMainForm::Generate() +{ + this->ResetOutputs(); + + this->UpdateProgress("Generating", 0); + this->CMakeInstance->SetProgressCallback( + [this](const std::string& msg, float prog) { + this->UpdateProgress(msg, prog); + }); + + // run the generate process + int retVal = this->CMakeInstance->Generate(); + + this->CMakeInstance->SetProgressCallback(nullptr); + keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ + + if (retVal != 0 || this->HasNonStatusOutputs) { + // see if there was an error + if (cmSystemTools::GetErrorOccuredFlag()) { + this->OkToGenerate = false; + } + // reset error condition + cmSystemTools::ResetErrorOccuredFlag(); + int xx; + int yy; + getmaxyx(stdscr, yy, xx); + const char* title = "Generate produced the following output"; + if (cmSystemTools::GetErrorOccuredFlag()) { + title = "Generate failed with the following output"; + } + cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm( + this->Outputs, title, + cmCursesLongMessageForm::ScrollBehavior::ScrollDown); + CurrentForm = msgs; + msgs->Render(1, 1, xx, yy); + msgs->HandleInput(); + // If they typed the wrong source directory, we report + // an error and exit + if (retVal == -2) { + return retVal; + } + } + + this->InitializeUI(); + CurrentForm = this; + int xi; + int yi; + getmaxyx(stdscr, yi, xi); + this->Render(1, 1, xi, yi); + + return 0; +} + +void cmCursesMainForm::AddError(const std::string& message, + const char* /*unused*/) +{ + this->Outputs.emplace_back(message); + this->HasNonStatusOutputs = true; + this->DisplayOutputs(message); +} + +void cmCursesMainForm::RemoveEntry(const char* value) +{ + if (!value) { + return; + } + + auto removeIt = + std::find_if(this->Entries.begin(), this->Entries.end(), + [value](cmCursesCacheEntryComposite& entry) -> bool { + const char* val = entry.GetValue(); + return val != nullptr && !strcmp(value, val); + }); + + if (removeIt != this->Entries.end()) { + this->CMakeInstance->UnwatchUnusedCli(value); + this->Entries.erase(removeIt); + } +} + +// copy from the list box to the cache manager +void cmCursesMainForm::FillCacheManagerFromUI() +{ + for (cmCursesCacheEntryComposite& entry : this->Entries) { + const std::string& cacheKey = entry.Key; + cmProp existingValue = + this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey); + if (existingValue) { + std::string oldValue = *existingValue; + std::string newValue = entry.Entry->GetValue(); + std::string fixedOldValue; + std::string fixedNewValue; + cmStateEnums::CacheEntryType t = + this->CMakeInstance->GetState()->GetCacheEntryType(cacheKey); + this->FixValue(t, oldValue, fixedOldValue); + this->FixValue(t, newValue, fixedNewValue); + + if (!(fixedOldValue == fixedNewValue)) { + // The user has changed the value. Mark it as modified. + this->CMakeInstance->GetState()->SetCacheEntryBoolProperty( + cacheKey, "MODIFIED", true); + this->CMakeInstance->GetState()->SetCacheEntryValue(cacheKey, + fixedNewValue); + } + } + } +} + +void cmCursesMainForm::FixValue(cmStateEnums::CacheEntryType type, + const std::string& in, std::string& out) const +{ + out = in.substr(0, in.find_last_not_of(' ') + 1); + if (type == cmStateEnums::PATH || type == cmStateEnums::FILEPATH) { + cmSystemTools::ConvertToUnixSlashes(out); + } + if (type == cmStateEnums::BOOL) { + if (cmIsOff(out)) { + out = "OFF"; + } else { + out = "ON"; + } + } +} + +void cmCursesMainForm::HandleInput() +{ + int x = 0; + int y = 0; + + if (!this->Form) { + return; + } + + FIELD* currentField; + cmCursesWidget* currentWidget; + + char debugMessage[128]; + + for (;;) { + this->UpdateStatusBar(); + this->PrintKeys(); + if (this->SearchMode) { + std::string searchstr = "Search: " + this->SearchString; + this->UpdateStatusBar(searchstr); + this->PrintKeys(1); + curses_move(y - 5, static_cast<unsigned int>(searchstr.size())); + // curses_move(1,1); + touchwin(stdscr); + refresh(); + } + int key = getch(); + + getmaxyx(stdscr, y, x); + // If window too small, handle 'q' only + if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) { + // quit + if (key == 'q') { + break; + } + continue; + } + + currentField = current_field(this->Form); + currentWidget = + reinterpret_cast<cmCursesWidget*>(field_userptr(currentField)); + + bool widgetHandled = false; + + if (this->SearchMode) { + if (key == 10 || key == KEY_ENTER) { + this->SearchMode = false; + if (!this->SearchString.empty()) { + this->JumpToCacheEntry(this->SearchString.c_str()); + this->OldSearchString = this->SearchString; + } + this->SearchString.clear(); + } + /* + else if ( key == KEY_ESCAPE ) + { + this->SearchMode = false; + } + */ + else if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') || + (key >= '0' && key <= '9') || (key == '_')) { + if (this->SearchString.size() < + static_cast<std::string::size_type>(x - 10)) { + this->SearchString += static_cast<char>(key); + } + } else if (key == ctrl('h') || key == KEY_BACKSPACE || key == KEY_DC) { + if (!this->SearchString.empty()) { + this->SearchString.pop_back(); + } + } + } else if (currentWidget && !this->SearchMode) { + // Ask the current widget if it wants to handle input + widgetHandled = currentWidget->HandleInput(key, this, stdscr); + if (widgetHandled) { + this->OkToGenerate = false; + this->UpdateStatusBar(); + this->PrintKeys(); + } + } + if ((!currentWidget || !widgetHandled) && !this->SearchMode) { + // If the current widget does not want to handle input, + // we handle it. + sprintf(debugMessage, "Main form handling input, key: %d", key); + cmCursesForm::LogMessage(debugMessage); + // quit + if (key == 'q') { + break; + } + // if not end of page, next field otherwise next page + // each entry consists of fields: label, isnew, value + // therefore, the label field for the prev. entry is index-5 + // and the label field for the next entry is index+1 + // (index always corresponds to the value field) + // scroll down with arrow down, ctrl+n (emacs binding), or j (vim + // binding) + if (key == KEY_DOWN || key == ctrl('n') || key == 'j') { + FIELD* cur = current_field(this->Form); + size_t findex = field_index(cur); + if (findex == 3 * this->NumberOfVisibleEntries - 1) { + continue; + } + if (new_page(this->Fields[findex + 1])) { + form_driver(this->Form, REQ_NEXT_PAGE); + } else { + form_driver(this->Form, REQ_NEXT_FIELD); + } + } + // if not beginning of page, previous field, otherwise previous page + // each entry consists of fields: label, isnew, value + // therefore, the label field for the prev. entry is index-5 + // and the label field for the next entry is index+1 + // (index always corresponds to the value field) + // scroll down with arrow up, ctrl+p (emacs binding), or k (vim binding) + else if (key == KEY_UP || key == ctrl('p') || key == 'k') { + FIELD* cur = current_field(this->Form); + int findex = field_index(cur); + if (findex == 2) { + continue; + } + if (new_page(this->Fields[findex - 2])) { + form_driver(this->Form, REQ_PREV_PAGE); + set_current_field(this->Form, this->Fields[findex - 3]); + } else { + form_driver(this->Form, REQ_PREV_FIELD); + } + } + // pg down + else if (key == KEY_NPAGE || key == ctrl('d')) { + form_driver(this->Form, REQ_NEXT_PAGE); + } + // pg up + else if (key == KEY_PPAGE || key == ctrl('u')) { + form_driver(this->Form, REQ_PREV_PAGE); + } + // configure + else if (key == 'c') { + this->Configure(); + } + // display help + else if (key == 'h') { + getmaxyx(stdscr, y, x); + + FIELD* cur = current_field(this->Form); + int findex = field_index(cur); + cmCursesWidget* lbl = reinterpret_cast<cmCursesWidget*>( + field_userptr(this->Fields[findex - 2])); + const char* curField = lbl->GetValue(); + cmProp helpString = nullptr; + + cmProp existingValue = + this->CMakeInstance->GetState()->GetCacheEntryValue(curField); + if (existingValue) { + helpString = this->CMakeInstance->GetState()->GetCacheEntryProperty( + curField, "HELPSTRING"); + } + if (helpString) { + this->HelpMessage[1] = + cmStrCat("Current option is: ", curField, '\n', + "Help string for this option is: ", *helpString, '\n'); + } else { + this->HelpMessage[1] = ""; + } + + cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm( + this->HelpMessage, "Help", + cmCursesLongMessageForm::ScrollBehavior::NoScroll); + CurrentForm = msgs; + msgs->Render(1, 1, x, y); + msgs->HandleInput(); + CurrentForm = this; + this->Render(1, 1, x, y); + set_current_field(this->Form, cur); + } + // display last errors + else if (key == 'l') { + getmaxyx(stdscr, y, x); + cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm( + this->Outputs, "CMake produced the following output", + cmCursesLongMessageForm::ScrollBehavior::NoScroll); + CurrentForm = msgs; + msgs->Render(1, 1, x, y); + msgs->HandleInput(); + CurrentForm = this; + this->Render(1, 1, x, y); + } else if (key == '/') { + this->SearchMode = true; + this->UpdateStatusBar("Search"); + this->PrintKeys(1); + touchwin(stdscr); + refresh(); + } else if (key == 'n') { + if (!this->OldSearchString.empty()) { + this->JumpToCacheEntry(this->OldSearchString.c_str()); + } + } + // switch advanced on/off + else if (key == 't') { + if (this->AdvancedMode) { + this->AdvancedMode = false; + } else { + this->AdvancedMode = true; + } + getmaxyx(stdscr, y, x); + this->RePost(); + this->Render(1, 1, x, y); + } + // generate and exit + else if (key == 'g') { + if (this->OkToGenerate) { + this->Generate(); + break; + } + } + // delete cache entry + else if (key == 'd' && this->NumberOfVisibleEntries) { + this->OkToGenerate = false; + FIELD* cur = current_field(this->Form); + size_t findex = field_index(cur); + + // make the next or prev. current field after deletion + // each entry consists of fields: label, isnew, value + // therefore, the label field for the prev. entry is findex-5 + // and the label field for the next entry is findex+1 + // (findex always corresponds to the value field) + FIELD* nextCur; + if (findex == 2) { + nextCur = nullptr; + } else if (findex == 3 * this->NumberOfVisibleEntries - 1) { + nextCur = this->Fields[findex - 5]; + } else { + nextCur = this->Fields[findex + 1]; + } + + // Get the label widget + // each entry consists of fields: label, isnew, value + // therefore, the label field for the is findex-2 + // (findex always corresponds to the value field) + cmCursesWidget* lbl = reinterpret_cast<cmCursesWidget*>( + field_userptr(this->Fields[findex - 2])); + if (lbl) { + this->CMakeInstance->GetState()->RemoveCacheEntry(lbl->GetValue()); + + std::string nextVal; + if (nextCur) { + nextVal = + (reinterpret_cast<cmCursesWidget*>(field_userptr(nextCur)) + ->GetValue()); + } + + getmaxyx(stdscr, y, x); + this->RemoveEntry(lbl->GetValue()); + this->RePost(); + this->Render(1, 1, x, y); + + if (nextCur) { + // make the next or prev. current field after deletion + auto nextEntryIt = std::find_if( + this->Entries.begin(), this->Entries.end(), + [&nextVal](cmCursesCacheEntryComposite const& entry) { + return nextVal == entry.Key; + }); + + if (nextEntryIt != this->Entries.end()) { + set_current_field(this->Form, nextEntryIt->Entry->Field); + } + } + } + } + } + + touchwin(stdscr); + wrefresh(stdscr); + } +} + +int cmCursesMainForm::LoadCache(const char* /*unused*/) + +{ + int r = this->CMakeInstance->LoadCache(); + if (r < 0) { + return r; + } + this->CMakeInstance->SetCacheArgs(this->Args); + this->CMakeInstance->PreLoadCMakeFiles(); + return r; +} + +void cmCursesMainForm::JumpToCacheEntry(const char* astr) +{ + std::string str; + if (astr) { + str = cmSystemTools::LowerCase(astr); + } + + if (str.empty()) { + return; + } + FIELD* cur = current_field(this->Form); + int start_index = field_index(cur); + int findex = start_index; + for (;;) { + if (!str.empty()) { + cmCursesWidget* lbl = nullptr; + if (findex >= 0) { + lbl = reinterpret_cast<cmCursesWidget*>( + field_userptr(this->Fields[findex - 2])); + } + if (lbl) { + const char* curField = lbl->GetValue(); + if (curField) { + std::string cfld = cmSystemTools::LowerCase(curField); + if (cfld.find(str) != std::string::npos && findex != start_index) { + break; + } + } + } + } + if (size_t(findex) >= 3 * this->NumberOfVisibleEntries - 1) { + set_current_field(this->Form, this->Fields[2]); + } else if (new_page(this->Fields[findex + 1])) { + form_driver(this->Form, REQ_NEXT_PAGE); + } else { + form_driver(this->Form, REQ_NEXT_FIELD); + } + cur = current_field(this->Form); + findex = field_index(cur); + if (findex == start_index) { + break; + } + } +} + +void cmCursesMainForm::ResetOutputs() +{ + this->LogForm.reset(); + this->Outputs.clear(); + this->HasNonStatusOutputs = false; + this->LastProgress.clear(); +} + +void cmCursesMainForm::DisplayOutputs(std::string const& newOutput) +{ + int xi; + int yi; + getmaxyx(stdscr, yi, xi); + + if (CurrentForm != this->LogForm.get()) { + auto newLogForm = new cmCursesLongMessageForm( + this->Outputs, this->LastProgress.c_str(), + cmCursesLongMessageForm::ScrollBehavior::ScrollDown); + CurrentForm = newLogForm; + this->LogForm.reset(newLogForm); + this->LogForm->Render(1, 1, xi, yi); + } else { + this->LogForm->UpdateContent(newOutput, this->LastProgress); + } +} + +const char* cmCursesMainForm::s_ConstHelpMessage = + "CMake is used to configure and generate build files for software projects. " + "The basic steps for configuring a project with ccmake are as follows:\n\n" + "1. Run ccmake in the directory where you want the object and executable " + "files to be placed (build directory). If the source directory is not the " + "same as this build directory, you have to specify it as an argument on the " + "command line.\n\n" + "2. When ccmake is run, it will read the configuration files and display " + "the current build options. " + "If you have run CMake before and have updated the configuration files " + "since then, any new entries will be displayed on top and will be marked " + "with a *. " + "On the other hand, the first time you run ccmake, all build options will " + "be new and will be marked as such. " + "At this point, you can modify any options (see keys below) you want to " + "change. " + "When you are satisfied with your changes, press 'c' to have CMake process " + "the configuration files. " + "Please note that changing some options may cause new ones to appear. These " + "will be shown on top and will be marked with *. " + "Repeat this procedure until you are satisfied with all the options and " + "there are no new entries. " + "At this point, a new command will appear: G)enerate and Exit. You can now " + "hit 'g' to have CMake generate all the build files (i.e. makefiles or " + "project files) and exit. " + "At any point during the process, you can exit ccmake with 'q'. However, " + "this will not generate/change any build files.\n\n" + "ccmake KEYS:\n\n" + "Navigation: " + "You can use the arrow keys and page up, down to navigate the options. " + "Alternatively, you can use the following keys: \n" + " C-n or j : next option\n" + " C-p or k : previous options\n" + " C-d : down one page\n" + " C-u : up one page\n\n" + "Editing options: " + "To change an option press enter or return. If the current options is a " + "boolean, this will toggle its value. " + "Otherwise, ccmake will enter edit mode. Alternatively, you can toggle " + "a bool variable by pressing space, and enter edit mode with i." + "In this mode you can edit an option using arrow keys and backspace. " + "Alternatively, you can use the following keys:\n" + " C-b : back one character\n" + " C-f : forward one character\n" + " C-a : go to the beginning of the field\n" + " C-e : go to the end of the field\n" + " C-d : delete previous character\n" + " C-k : kill the rest of the field\n" + " Esc : Restore field (discard last changes)\n" + " Enter : Leave edit mode\n" + "Commands:\n" + " q : quit ccmake without generating build files\n" + " h : help, shows this screen\n" + " c : process the configuration files with the current options\n" + " g : generate build files and exit, only available when there are no " + "new options and no errors have been detected during last configuration.\n" + " l : shows cmake output\n" + " d : delete an option\n" + " t : toggles advanced mode. In normal mode, only the most important " + "options are shown. In advanced mode, all options are shown. We recommend " + "using normal mode unless you are an expert.\n" + " / : search for a variable name.\n"; diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h new file mode 100644 index 0000000..2e06b90 --- /dev/null +++ b/Source/CursesDialog/cmCursesMainForm.h @@ -0,0 +1,174 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesMainForm_h +#define cmCursesMainForm_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <cstddef> +#include <memory> +#include <string> +#include <vector> + +#include <cm/optional> + +#include "cmCursesCacheEntryComposite.h" +#include "cmCursesForm.h" +#include "cmCursesStandardIncludes.h" +#include "cmStateTypes.h" + +class cmake; +class cmCursesLongMessageForm; + +/** \class cmCursesMainForm + * \brief The main page of ccmake + * + * cmCursesMainForm is the main page of ccmake. + */ +class cmCursesMainForm : public cmCursesForm +{ +public: + cmCursesMainForm(std::vector<std::string> args, int initwidth); + ~cmCursesMainForm() override; + + cmCursesMainForm(cmCursesMainForm const&) = delete; + cmCursesMainForm& operator=(cmCursesMainForm const&) = delete; + + /** + * Set the widgets which represent the cache entries. + */ + void InitializeUI(); + + /** + * Handle user input. + */ + void HandleInput() override; + + /** + * Display form. Use a window of size width x height, starting + * at top, left. + */ + void Render(int left, int top, int width, int height) override; + + /** + * Returns true if an entry with the given key is in the + * list of current composites. + */ + bool LookForCacheEntry(const std::string& key); + + enum + { + MIN_WIDTH = 65, + MIN_HEIGHT = 6, + IDEAL_WIDTH = 80, + MAX_WIDTH = 512 + }; + + /** + * This method should normally be called only by the form. The only + * exception is during a resize. The optional argument specifies the + * string to be displayed in the status bar. + */ + void UpdateStatusBar() override { this->UpdateStatusBar(cm::nullopt); } + void UpdateStatusBar(cm::optional<std::string> message); + + /** + * Display current commands and their keys on the toolbar. This + * method should normally called only by the form. The only + * exception is during a resize. If the optional argument process is + * specified and is either 1 (configure) or 2 (generate), then keys + * will be displayed accordingly. + */ + void PrintKeys(int process = 0); + + /** + * During a CMake run, an error handle should add errors + * to be displayed afterwards. + */ + void AddError(const std::string& message, const char* title) override; + + /** + * Used to do a configure. If argument is specified, it does only the check + * and not configure. + */ + int Configure(int noconfigure = 0); + + /** + * Used to generate + */ + int Generate(); + + /** + * Used by main program + */ + int LoadCache(const char* dir); + + /** + * Progress callback + */ + void UpdateProgress(const std::string& msg, float prog); + +protected: + // Copy the cache values from the user interface to the actual + // cache. + void FillCacheManagerFromUI(); + // Fix formatting of values to a consistent form. + void FixValue(cmStateEnums::CacheEntryType type, const std::string& in, + std::string& out) const; + // Re-post the existing fields. Used to toggle between + // normal and advanced modes. Render() should be called + // afterwards. + void RePost(); + // Remove an entry from the interface and the cache. + void RemoveEntry(const char* value); + + // Jump to the cache entry whose name matches the string. + void JumpToCacheEntry(const char* str); + + // Clear and reset the output log and state + void ResetOutputs(); + + // Display the current progress and output + void DisplayOutputs(std::string const& newOutput); + + // Copies of cache entries stored in the user interface + std::vector<cmCursesCacheEntryComposite> Entries; + + // The form used to display logs during processing + std::unique_ptr<cmCursesLongMessageForm> LogForm; + // Output produced by the last pass + std::vector<std::string> Outputs; + // Did the last pass produced outputs of interest (errors, warnings, ...) + bool HasNonStatusOutputs; + // Last progress bar + std::string LastProgress; + + // Command line arguments to be passed to cmake each time + // it is run + std::vector<std::string> Args; + // Message displayed when user presses 'h' + // It is: Welcome + info about current entry + common help + std::vector<std::string> HelpMessage; + + // Common help + static const char* s_ConstHelpMessage; + + // Fields displayed. Includes labels, new entry markers, entries + std::vector<FIELD*> Fields; + // Number of entries shown (depends on mode -normal or advanced-) + size_t NumberOfVisibleEntries; + bool AdvancedMode; + // Did the iteration converge (no new entries) ? + bool OkToGenerate; + // Number of pages displayed + int NumberOfPages; + + int InitialWidth; + std::unique_ptr<cmake> CMakeInstance; + + std::string SearchString; + std::string OldSearchString; + bool SearchMode; +}; + +#endif // cmCursesMainForm_h diff --git a/Source/CursesDialog/cmCursesOptionsWidget.cxx b/Source/CursesDialog/cmCursesOptionsWidget.cxx new file mode 100644 index 0000000..a15241f --- /dev/null +++ b/Source/CursesDialog/cmCursesOptionsWidget.cxx @@ -0,0 +1,93 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesOptionsWidget.h" + +#include "cmCursesColor.h" +#include "cmCursesWidget.h" +#include "cmStateTypes.h" + +#define ctrl(z) ((z)&037) + +cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left, + int top) + : cmCursesWidget(width, height, left, top) +{ + this->Type = cmStateEnums::BOOL; // this is a bit of a hack + // there is no option type, and string type causes ccmake to cast + // the widget into a string widget at some point. BOOL is safe for + // now. + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Options)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Options)); + } else { + set_field_fore(this->Field, A_NORMAL); + set_field_back(this->Field, A_STANDOUT); + } + field_opts_off(this->Field, O_STATIC); +} + +bool cmCursesOptionsWidget::HandleInput(int& key, cmCursesMainForm* /*fm*/, + WINDOW* w) +{ + if (this->Options.empty()) { + return false; + } + switch (key) { + case 10: // 10 == enter + case KEY_ENTER: + this->NextOption(); + touchwin(w); + wrefresh(w); + return true; + case KEY_LEFT: + case ctrl('b'): + touchwin(w); + wrefresh(w); + this->PreviousOption(); + return true; + case KEY_RIGHT: + case ctrl('f'): + this->NextOption(); + touchwin(w); + wrefresh(w); + return true; + default: + return false; + } +} + +void cmCursesOptionsWidget::AddOption(std::string const& option) +{ + this->Options.push_back(option); +} + +void cmCursesOptionsWidget::NextOption() +{ + this->CurrentOption++; + if (this->CurrentOption > this->Options.size() - 1) { + this->CurrentOption = 0; + } + this->SetValue(this->Options[this->CurrentOption]); +} +void cmCursesOptionsWidget::PreviousOption() +{ + if (this->CurrentOption == 0) { + this->CurrentOption = this->Options.size() - 1; + } else { + this->CurrentOption--; + } + this->SetValue(this->Options[this->CurrentOption]); +} + +void cmCursesOptionsWidget::SetOption(const std::string& value) +{ + this->CurrentOption = 0; // default to 0 index + this->SetValue(value); + int index = 0; + for (auto const& opt : this->Options) { + if (opt == value) { + this->CurrentOption = index; + } + index++; + } +} diff --git a/Source/CursesDialog/cmCursesOptionsWidget.h b/Source/CursesDialog/cmCursesOptionsWidget.h new file mode 100644 index 0000000..0de8e64 --- /dev/null +++ b/Source/CursesDialog/cmCursesOptionsWidget.h @@ -0,0 +1,39 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesOptionsWidget_h +#define cmCursesOptionsWidget_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> +#include <vector> + +#include "cmCursesStandardIncludes.h" +#include "cmCursesWidget.h" + +class cmCursesMainForm; + +class cmCursesOptionsWidget : public cmCursesWidget +{ +public: + cmCursesOptionsWidget(int width, int height, int left, int top); + + cmCursesOptionsWidget(cmCursesOptionsWidget const&) = delete; + cmCursesOptionsWidget& operator=(cmCursesOptionsWidget const&) = delete; + + // Description: + // Handle user input. Called by the container of this widget + // when this widget has focus. Returns true if the input was + // handled. + bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override; + void SetOption(const std::string&); + void AddOption(std::string const&); + void NextOption(); + void PreviousOption(); + +protected: + std::vector<std::string> Options; + std::vector<std::string>::size_type CurrentOption; +}; + +#endif // cmCursesOptionsWidget_h diff --git a/Source/CursesDialog/cmCursesPathWidget.cxx b/Source/CursesDialog/cmCursesPathWidget.cxx new file mode 100644 index 0000000..8ed42de --- /dev/null +++ b/Source/CursesDialog/cmCursesPathWidget.cxx @@ -0,0 +1,89 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesPathWidget.h" + +#include <vector> + +#include "cmCursesColor.h" +#include "cmCursesMainForm.h" +#include "cmCursesStringWidget.h" +#include "cmStateTypes.h" +#include "cmSystemTools.h" + +cmCursesPathWidget::cmCursesPathWidget(int width, int height, int left, + int top) + : cmCursesStringWidget(width, height, left, top) +{ + this->Type = cmStateEnums::PATH; + this->Cycle = false; + this->CurrentIndex = 0; + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Path)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Path)); + } else { + set_field_fore(this->Field, A_NORMAL); + set_field_back(this->Field, A_STANDOUT); + } +} + +void cmCursesPathWidget::OnType(int& key, cmCursesMainForm* fm, WINDOW* w) +{ + this->Cycle = false; + this->CurrentIndex = 0; + this->LastGlob = ""; + this->cmCursesStringWidget::OnType(key, fm, w); +} + +void cmCursesPathWidget::OnTab(cmCursesMainForm* fm, WINDOW* w) +{ + if (!this->GetString()) { + return; + } + FORM* form = fm->GetForm(); + form_driver(form, REQ_NEXT_FIELD); + form_driver(form, REQ_PREV_FIELD); + std::string cstr = this->GetString(); + cstr = cstr.substr(0, cstr.find_last_not_of(" \t\n\r") + 1); + if (this->LastString != cstr) { + this->Cycle = false; + this->CurrentIndex = 0; + this->LastGlob = ""; + } + std::string glob; + if (this->Cycle) { + glob = this->LastGlob; + } else { + glob = cstr + "*"; + } + std::vector<std::string> dirs; + + cmSystemTools::SimpleGlob(glob, dirs, + (this->Type == cmStateEnums::PATH ? -1 : 0)); + if (this->CurrentIndex < dirs.size()) { + cstr = dirs[this->CurrentIndex]; + } + if (cstr[cstr.size() - 1] == '*') { + cstr = cstr.substr(0, cstr.size() - 1); + } + + if (cmSystemTools::FileIsDirectory(cstr)) { + cstr += "/"; + } + + this->SetString(cstr); + touchwin(w); + wrefresh(w); + form_driver(form, REQ_END_FIELD); + this->LastGlob = glob; + this->LastString = cstr; + this->Cycle = true; + this->CurrentIndex++; + if (this->CurrentIndex >= dirs.size()) { + this->CurrentIndex = 0; + } +} + +void cmCursesPathWidget::OnReturn(cmCursesMainForm* fm, WINDOW* w) +{ + this->cmCursesStringWidget::OnReturn(fm, w); +} diff --git a/Source/CursesDialog/cmCursesPathWidget.h b/Source/CursesDialog/cmCursesPathWidget.h new file mode 100644 index 0000000..fb365e9 --- /dev/null +++ b/Source/CursesDialog/cmCursesPathWidget.h @@ -0,0 +1,38 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesPathWidget_h +#define cmCursesPathWidget_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> + +#include "cmCursesStandardIncludes.h" +#include "cmCursesStringWidget.h" + +class cmCursesMainForm; + +class cmCursesPathWidget : public cmCursesStringWidget +{ +public: + cmCursesPathWidget(int width, int height, int left, int top); + + cmCursesPathWidget(cmCursesPathWidget const&) = delete; + cmCursesPathWidget& operator=(cmCursesPathWidget const&) = delete; + + /** + * This method is called when different keys are pressed. The + * subclass can have a special implementation handler for this. + */ + void OnTab(cmCursesMainForm* fm, WINDOW* w) override; + void OnReturn(cmCursesMainForm* fm, WINDOW* w) override; + void OnType(int& key, cmCursesMainForm* fm, WINDOW* w) override; + +protected: + std::string LastString; + std::string LastGlob; + bool Cycle; + std::string::size_type CurrentIndex; +}; + +#endif // cmCursesPathWidget_h diff --git a/Source/CursesDialog/cmCursesStandardIncludes.h b/Source/CursesDialog/cmCursesStandardIncludes.h new file mode 100644 index 0000000..5b0ad58 --- /dev/null +++ b/Source/CursesDialog/cmCursesStandardIncludes.h @@ -0,0 +1,45 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesStandardIncludes_h +#define cmCursesStandardIncludes_h + +#include "cmConfigure.h" // IWYU pragma: keep + +// Record whether __attribute__ is currently defined. See purpose below. +#ifndef __attribute__ +# define cm_no__attribute__ +#endif + +#if defined(__hpux) +# define _BOOL_DEFINED +# include <sys/time.h> +#endif + +#include <form.h> + +// on some machines move erase and clear conflict with stl +// so remove them from the namespace +inline void curses_move(unsigned int x, unsigned int y) +{ + move(x, y); +} + +inline void curses_clear() +{ + erase(); + clearok(stdscr, TRUE); +} + +#undef move +#undef erase +#undef clear + +// The curses headers on some platforms (e.g. Solaris) may +// define __attribute__ as a macro. This breaks C++ headers +// in some cases, so undefine it now. +#if defined(cm_no__attribute__) && defined(__attribute__) +# undef __attribute__ +#endif +#undef cm_no__attribute__ + +#endif // cmCursesStandardIncludes_h diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx new file mode 100644 index 0000000..c629478 --- /dev/null +++ b/Source/CursesDialog/cmCursesStringWidget.cxx @@ -0,0 +1,209 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesStringWidget.h" + +#include <cstdio> + +#include "cmCursesColor.h" +#include "cmCursesForm.h" +#include "cmCursesMainForm.h" +#include "cmCursesStandardIncludes.h" +#include "cmCursesWidget.h" +#include "cmStateTypes.h" + +inline int ctrl(int z) +{ + return (z & 037); +} + +cmCursesStringWidget::cmCursesStringWidget(int width, int height, int left, + int top) + : cmCursesWidget(width, height, left, top) +{ + this->InEdit = false; + this->Type = cmStateEnums::STRING; + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::String)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::String)); + } else { + set_field_fore(this->Field, A_NORMAL); + set_field_back(this->Field, A_STANDOUT); + } + field_opts_off(this->Field, O_STATIC); +} + +void cmCursesStringWidget::OnTab(cmCursesMainForm* /*unused*/, + WINDOW* /*unused*/) +{ + // FORM* form = fm->GetForm(); +} + +void cmCursesStringWidget::OnReturn(cmCursesMainForm* fm, WINDOW* /*unused*/) +{ + if (this->InEdit) { + cmCursesForm::LogMessage("String widget leaving edit."); + this->InEdit = false; + fm->PrintKeys(); + this->OriginalString.clear(); + // trick to force forms to update the field buffer + FORM* form = fm->GetForm(); + form_driver(form, REQ_NEXT_FIELD); + form_driver(form, REQ_PREV_FIELD); + this->Done = true; + } else { + cmCursesForm::LogMessage("String widget entering edit."); + this->InEdit = true; + fm->PrintKeys(); + this->OriginalString = field_buffer(this->Field, 0); + } +} + +void cmCursesStringWidget::OnType(int& key, cmCursesMainForm* fm, + WINDOW* /*unused*/) +{ + form_driver(fm->GetForm(), key); +} + +bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm, + WINDOW* w) +{ + int x; + int y; + + FORM* form = fm->GetForm(); + // when not in edit mode, edit mode is entered by pressing enter or i (vim + // binding) + // 10 == enter + if (!this->InEdit && (key != 10 && key != KEY_ENTER && key != 'i')) { + return false; + } + + this->OriginalString.clear(); + this->Done = false; + + char debugMessage[128]; + + // <Enter> is used to change edit mode (like <Esc> in vi). + while (!this->Done) { + sprintf(debugMessage, "String widget handling input, key: %d", key); + cmCursesForm::LogMessage(debugMessage); + + fm->PrintKeys(); + + getmaxyx(stdscr, y, x); + // If window too small, handle 'q' only + if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) { + // quit + if (key == 'q') { + return false; + } + key = getch(); + continue; + } + + // If resize occurred during edit, move out of edit mode + if (!this->InEdit && (key != 10 && key != KEY_ENTER && key != 'i')) { + return false; + } + // enter edit with return and i (vim binding) + if (!this->InEdit && (key == 10 || key == KEY_ENTER || key == 'i')) { + this->OnReturn(fm, w); + } + // leave edit with return (but not i -- not a toggle) + else if (this->InEdit && (key == 10 || key == KEY_ENTER)) { + this->OnReturn(fm, w); + } else if (key == KEY_DOWN || key == ctrl('n') || key == KEY_UP || + key == ctrl('p') || key == KEY_NPAGE || key == ctrl('d') || + key == KEY_PPAGE || key == ctrl('u')) { + this->InEdit = false; + this->OriginalString.clear(); + // trick to force forms to update the field buffer + form_driver(form, REQ_NEXT_FIELD); + form_driver(form, REQ_PREV_FIELD); + return false; + } + // esc + else if (key == 27) { + if (this->InEdit) { + this->InEdit = false; + fm->PrintKeys(); + this->SetString(this->OriginalString); + this->OriginalString.clear(); + touchwin(w); + wrefresh(w); + return true; + } + } else if (key == 9) { + this->OnTab(fm, w); + } else if (key == KEY_LEFT || key == ctrl('b')) { + form_driver(form, REQ_PREV_CHAR); + } else if (key == KEY_RIGHT || key == ctrl('f')) { + form_driver(form, REQ_NEXT_CHAR); + } else if (key == ctrl('k')) { + form_driver(form, REQ_CLR_EOL); + } else if (key == ctrl('a') || key == KEY_HOME) { + form_driver(form, REQ_BEG_FIELD); + } else if (key == ctrl('e') || key == KEY_END) { + form_driver(form, REQ_END_FIELD); + } else if (key == 127 || key == KEY_BACKSPACE) { + FIELD* cur = current_field(form); + form_driver(form, REQ_DEL_PREV); + if (current_field(form) != cur) { + set_current_field(form, cur); + } + } else if (key == ctrl('d') || key == KEY_DC) { + form_driver(form, REQ_DEL_CHAR); + } else { + this->OnType(key, fm, w); + } + if (!this->Done) { + touchwin(w); + wrefresh(w); + + key = getch(); + } + } + return true; +} + +void cmCursesStringWidget::SetString(const std::string& value) +{ + this->SetValue(value); +} + +const char* cmCursesStringWidget::GetString() +{ + return this->GetValue(); +} + +const char* cmCursesStringWidget::GetValue() +{ + return field_buffer(this->Field, 0); +} + +bool cmCursesStringWidget::PrintKeys() +{ + int x; + int y; + getmaxyx(stdscr, y, x); + if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) { + return false; + } + if (this->InEdit) { + char fmt_s[] = "%s"; + // Clean the toolbar + curses_move(y - 4, 0); + clrtoeol(); + curses_move(y - 3, 0); + printw(fmt_s, "Editing option, press [enter] to confirm"); + clrtoeol(); + curses_move(y - 2, 0); + printw(fmt_s, " press [esc] to cancel"); + clrtoeol(); + curses_move(y - 1, 0); + clrtoeol(); + + return true; + } + return false; +} diff --git a/Source/CursesDialog/cmCursesStringWidget.h b/Source/CursesDialog/cmCursesStringWidget.h new file mode 100644 index 0000000..ce06c6d --- /dev/null +++ b/Source/CursesDialog/cmCursesStringWidget.h @@ -0,0 +1,69 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesStringWidget_h +#define cmCursesStringWidget_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> + +#include "cmCursesStandardIncludes.h" +#include "cmCursesWidget.h" + +class cmCursesMainForm; + +/** \class cmCursesStringWidget + * \brief A simple entry widget. + * + * cmCursesStringWdiget is a simple text entry widget. + */ + +class cmCursesStringWidget : public cmCursesWidget +{ +public: + cmCursesStringWidget(int width, int height, int left, int top); + + /** + * Handle user input. Called by the container of this widget + * when this widget has focus. Returns true if the input was + * handled. + */ + bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override; + + /** + * Set/Get the string. + */ + void SetString(const std::string& value); + const char* GetString(); + const char* GetValue() override; + + /** + * Set/Get InEdit flag. Can be used to tell the widget to leave + * edit mode (in case of a resize for example). + */ + void SetInEdit(bool inedit) { this->InEdit = inedit; } + bool GetInEdit() { return this->InEdit; } + + /** + * This method is called when different keys are pressed. The + * subclass can have a special implementation handler for this. + */ + virtual void OnTab(cmCursesMainForm* fm, WINDOW* w); + virtual void OnReturn(cmCursesMainForm* fm, WINDOW* w); + virtual void OnType(int& key, cmCursesMainForm* fm, WINDOW* w); + + /** + * If there are any, print the widget specific commands + * in the toolbar and return true. Otherwise, return false + * and the parent widget will print. + */ + bool PrintKeys() override; + +protected: + // true if the widget is in edit mode + bool InEdit; + std::string OriginalString; + bool Done; +}; + +#endif // cmCursesStringWidget_h diff --git a/Source/CursesDialog/cmCursesWidget.cxx b/Source/CursesDialog/cmCursesWidget.cxx new file mode 100644 index 0000000..cc07411 --- /dev/null +++ b/Source/CursesDialog/cmCursesWidget.cxx @@ -0,0 +1,44 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesWidget.h" + +cmCursesWidget::cmCursesWidget(int width, int height, int left, int top) +{ + this->Field = new_field(height, width, top, left, 0, 0); + set_field_userptr(this->Field, reinterpret_cast<char*>(this)); + field_opts_off(this->Field, O_AUTOSKIP); + this->Page = 0; +} + +cmCursesWidget::~cmCursesWidget() +{ + if (this->Field) { + free_field(this->Field); + this->Field = nullptr; + } +} + +void cmCursesWidget::Move(int x, int y, bool isNewPage) +{ + if (!this->Field) { + return; + } + + move_field(this->Field, y, x); + if (isNewPage) { + set_new_page(this->Field, true); + } else { + set_new_page(this->Field, false); + } +} + +void cmCursesWidget::SetValue(const std::string& value) +{ + this->Value = value; + set_field_buffer(this->Field, 0, const_cast<char*>(value.c_str())); +} + +const char* cmCursesWidget::GetValue() +{ + return this->Value.c_str(); +} diff --git a/Source/CursesDialog/cmCursesWidget.h b/Source/CursesDialog/cmCursesWidget.h new file mode 100644 index 0000000..9d03c6e --- /dev/null +++ b/Source/CursesDialog/cmCursesWidget.h @@ -0,0 +1,72 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesWidget_h +#define cmCursesWidget_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> + +#include "cmCursesStandardIncludes.h" +#include "cmStateTypes.h" + +class cmCursesMainForm; + +class cmCursesWidget +{ +public: + cmCursesWidget(int width, int height, int left, int top); + virtual ~cmCursesWidget(); + + cmCursesWidget(cmCursesWidget const&) = delete; + cmCursesWidget& operator=(cmCursesWidget const&) = delete; + + /** + * Handle user input. Called by the container of this widget + * when this widget has focus. Returns true if the input was + * handled + */ + virtual bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) = 0; + + /** + * Change the position of the widget. Set isNewPage to true + * if this widget marks the beginning of a new page. + */ + virtual void Move(int x, int y, bool isNewPage); + + /** + * Set/Get the value (setting the value also changes the contents + * of the field buffer). + */ + virtual void SetValue(const std::string& value); + virtual const char* GetValue(); + + /** + * Get the type of the widget (STRING, PATH etc...) + */ + cmStateEnums::CacheEntryType GetType() { return this->Type; } + + /** + * If there are any, print the widget specific commands + * in the toolbar and return true. Otherwise, return false + * and the parent widget will print. + */ + virtual bool PrintKeys() { return false; } + + /** + * Set/Get the page this widget is in. + */ + void SetPage(int page) { this->Page = page; } + int GetPage() { return this->Page; } + + friend class cmCursesMainForm; + +protected: + cmStateEnums::CacheEntryType Type; + std::string Value; + FIELD* Field; + // The page in the main form this widget is in + int Page; +}; + +#endif // cmCursesWidget_h diff --git a/Source/CursesDialog/form/.NoDartCoverage b/Source/CursesDialog/form/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/Source/CursesDialog/form/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/Source/CursesDialog/form/.gitattributes b/Source/CursesDialog/form/.gitattributes new file mode 100644 index 0000000..12ede74 --- /dev/null +++ b/Source/CursesDialog/form/.gitattributes @@ -0,0 +1 @@ +* -format.clang-format-6.0 diff --git a/Source/CursesDialog/form/CMakeLists.txt b/Source/CursesDialog/form/CMakeLists.txt new file mode 100644 index 0000000..b468f5b --- /dev/null +++ b/Source/CursesDialog/form/CMakeLists.txt @@ -0,0 +1,61 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +project(CMAKE_FORM) + +configure_file(cmFormConfigure.h.in "${CMAKE_CURRENT_BINARY_DIR}/cmFormConfigure.h") + +add_library(cmForm + fld_arg.c + fld_attr.c + fld_current.c + fld_def.c + fld_dup.c + fld_ftchoice.c + fld_ftlink.c + fld_info.c + fld_just.c + fld_link.c + fld_max.c + fld_move.c + fld_newftyp.c + fld_opts.c + fld_pad.c + fld_page.c + fld_stat.c + fld_type.c + fld_user.c + frm_cursor.c + frm_data.c + frm_def.c + frm_driver.c + frm_hook.c + frm_opts.c + frm_page.c + frm_post.c + frm_req_name.c + frm_scale.c + frm_sub.c + frm_user.c + frm_win.c + fty_alnum.c + fty_alpha.c + fty_enum.c + fty_int.c + fty_ipv4.c + fty_num.c + fty_regex.c + ) + +target_include_directories(cmForm + PUBLIC + ${CURSES_INCLUDE_PATH} + ${CMAKE_FORM_BINARY_DIR} + ${CMAKE_FORM_SOURCE_DIR} + ) + +target_link_libraries(cmForm ${CURSES_LIBRARY}) + +if(CURSES_EXTRA_LIBRARY) + target_link_libraries(cmForm ${CURSES_EXTRA_LIBRARY}) +endif() diff --git a/Source/CursesDialog/form/READ.ME b/Source/CursesDialog/form/READ.ME new file mode 100644 index 0000000..dd91693 --- /dev/null +++ b/Source/CursesDialog/form/READ.ME @@ -0,0 +1,15 @@ +This is a clone of the form library that is available with typical +System V curses implementations (ETI). + +It is modelled after the documentation that comes for this library with +a 386 based SVR4 implementation (ESIX). + +The development environment was and is an ELF based Linux system. + +For things that still need doing, see the TO-DO file in the top-level +directory. + +Juergen Pfeifer + +eMail: juergen.pfeifer@gmx.net + diff --git a/Source/CursesDialog/form/cmFormConfigure.h.in b/Source/CursesDialog/form/cmFormConfigure.h.in new file mode 100644 index 0000000..511c525 --- /dev/null +++ b/Source/CursesDialog/form/cmFormConfigure.h.in @@ -0,0 +1,11 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef CMFORMCONFIGURE_H +#define CMFORMCONFIGURE_H + +#cmakedefine CURSES_HAVE_CURSES_H +#cmakedefine CURSES_HAVE_NCURSES_H +#cmakedefine CURSES_HAVE_NCURSES_NCURSES_H +#cmakedefine CURSES_HAVE_NCURSES_CURSES_H + +#endif diff --git a/Source/CursesDialog/form/eti.h b/Source/CursesDialog/form/eti.h new file mode 100644 index 0000000..cc1c830 --- /dev/null +++ b/Source/CursesDialog/form/eti.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#ifndef _ETI_ERRNO_H_ +#define _ETI_ERRNO_H_ + +#define E_OK (0) +#define E_SYSTEM_ERROR (-1) +#define E_BAD_ARGUMENT (-2) +#define E_POSTED (-3) +#define E_CONNECTED (-4) +#define E_BAD_STATE (-5) +#define E_NO_ROOM (-6) +#define E_NOT_POSTED (-7) +#define E_UNKNOWN_COMMAND (-8) +#define E_NO_MATCH (-9) +#define E_NOT_SELECTABLE (-10) +#define E_NOT_CONNECTED (-11) +#define E_REQUEST_DENIED (-12) +#define E_INVALID_FIELD (-13) +#define E_CURRENT (-14) + +#endif diff --git a/Source/CursesDialog/form/fld_arg.c b/Source/CursesDialog/form/fld_arg.c new file mode 100644 index 0000000..91ad79f --- /dev/null +++ b/Source/CursesDialog/form/fld_arg.c @@ -0,0 +1,91 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_fieldtype_arg( +| FIELDTYPE *typ, +| void * (* const make_arg)(va_list *), +| void * (* const copy_arg)(const void *), +| void (* const free_arg)(void *) ) +| +| Description : Connects to the type additional arguments necessary +| for a set_field_type call. The various function pointer +| arguments are: +| make_arg : allocates a structure for the field +| specific parameters. +| copy_arg : duplicate the structure created by +| make_arg +| free_arg : Release the memory allocated by make_arg +| or copy_arg +| +| At least make_arg must be non-NULL. +| You may pass NULL for copy_arg and free_arg if your +| make_arg function doesn't allocate memory and your +| arg fits into the storage for a (void*). +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid argument ++--------------------------------------------------------------------------*/ +int set_fieldtype_arg(FIELDTYPE * typ, + void * (* const make_arg)(va_list *), + void * (* const copy_arg)(const void *), + void (* const free_arg)(void *)) +{ + if ( !typ || !make_arg ) + RETURN(E_BAD_ARGUMENT); + + typ->status |= _HAS_ARGS; + typ->makearg = make_arg; + typ->copyarg = copy_arg; + typ->freearg = free_arg; + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : void *field_arg(const FIELD *field) +| +| Description : Retrieve pointer to the fields argument structure. +| +| Return Values : Pointer to structure or NULL if none is defined. ++--------------------------------------------------------------------------*/ +void *field_arg(const FIELD * field) +{ + return Normalize_Field(field)->arg; +} + +/* fld_arg.c ends here */ diff --git a/Source/CursesDialog/form/fld_attr.c b/Source/CursesDialog/form/fld_attr.c new file mode 100644 index 0000000..35ea903 --- /dev/null +++ b/Source/CursesDialog/form/fld_attr.c @@ -0,0 +1,110 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ +#include "form.priv.h" +MODULE_ID("$Id$") + +/*---------------------------------------------------------------------------- + Field-Attribute manipulation routines + --------------------------------------------------------------------------*/ +/* "Template" macro to generate a function to set a fields attribute */ +#define GEN_FIELD_ATTR_SET_FCT( name ) \ +int set_field_ ## name (FIELD * field, chtype attr)\ +{\ + int res = E_BAD_ARGUMENT;\ + if ( attr==A_NORMAL || ((attr & A_ATTRIBUTES)==attr) )\ + {\ + Normalize_Field( field );\ + if ((field -> name) != attr)\ + {\ + field -> name = attr;\ + res = _nc_Synchronize_Attributes( field );\ + }\ + else\ + res = E_OK;\ + }\ + RETURN(res);\ +} + +/* "Template" macro to generate a function to get a fields attribute */ +#define GEN_FIELD_ATTR_GET_FCT( name ) \ +chtype field_ ## name (const FIELD * field)\ +{\ + return ( A_ATTRIBUTES & (Normalize_Field( field ) -> name) );\ +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_fore(FIELD *field, chtype attr) +| +| Description : Sets the foreground of the field used to display the +| field contents. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid attributes +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +GEN_FIELD_ATTR_SET_FCT( fore ) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : chtype field_fore(const FIELD *) +| +| Description : Retrieve fields foreground attribute +| +| Return Values : The foreground attribute ++--------------------------------------------------------------------------*/ +GEN_FIELD_ATTR_GET_FCT( fore ) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_back(FIELD *field, chtype attr) +| +| Description : Sets the background of the field used to display the +| fields extend. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid attributes +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +GEN_FIELD_ATTR_SET_FCT( back ) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : chtype field_back(const +| +| Description : Retrieve fields background attribute +| +| Return Values : The background attribute ++--------------------------------------------------------------------------*/ +GEN_FIELD_ATTR_GET_FCT( back ) + +/* fld_attr.c ends here */ diff --git a/Source/CursesDialog/form/fld_current.c b/Source/CursesDialog/form/fld_current.c new file mode 100644 index 0000000..d4b1254 --- /dev/null +++ b/Source/CursesDialog/form/fld_current.c @@ -0,0 +1,124 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_current_field(FORM * form,FIELD * field) +| +| Description : Set the current field of the form to the specified one. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid form or field pointer +| E_REQUEST_DENIED - field not selectable +| E_BAD_STATE - called from a hook routine +| E_INVALID_FIELD - current field can't be left +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +int set_current_field(FORM * form, FIELD * field) +{ + int err = E_OK; + + if ( !form || !field ) + RETURN(E_BAD_ARGUMENT); + + if ( (form != field->form) || Field_Is_Not_Selectable(field) ) + RETURN(E_REQUEST_DENIED); + + if (!(form->status & _POSTED)) + { + form->current = field; + form->curpage = field->page; + } + else + { + if (form->status & _IN_DRIVER) + err = E_BAD_STATE; + else + { + if (form->current != field) + { + if (!_nc_Internal_Validation(form)) + err = E_INVALID_FIELD; + else + { + Call_Hook(form,fieldterm); + if (field->page != form->curpage) + { + Call_Hook(form,formterm); + err = _nc_Set_Form_Page(form,field->page,field); + Call_Hook(form,forminit); + } + else + { + err = _nc_Set_Current_Field(form,field); + } + Call_Hook(form,fieldinit); + _nc_Refresh_Current_Field(form); + } + } + } + } + RETURN(err); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FIELD *current_field(const FORM * form) +| +| Description : Return the current field. +| +| Return Values : Pointer to the current field. ++--------------------------------------------------------------------------*/ +FIELD *current_field(const FORM * form) +{ + return Normalize_Form(form)->current; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int field_index(const FIELD * field) +| +| Description : Return the index of the field in the field-array of +| the form. +| +| Return Values : >= 0 : field index +| -1 : fieldpointer invalid or field not connected ++--------------------------------------------------------------------------*/ +int field_index(const FIELD * field) +{ + return ( (field && field->form) ? field->index : -1 ); +} + +/* fld_current.c ends here */ diff --git a/Source/CursesDialog/form/fld_def.c b/Source/CursesDialog/form/fld_def.c new file mode 100644 index 0000000..00da3b4 --- /dev/null +++ b/Source/CursesDialog/form/fld_def.c @@ -0,0 +1,346 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/* this can't be readonly */ +static FIELD default_field = { + 0, /* status */ + 0, /* rows */ + 0, /* cols */ + 0, /* frow */ + 0, /* fcol */ + 0, /* drows */ + 0, /* dcols */ + 0, /* maxgrow*/ + 0, /* nrow */ + 0, /* nbuf */ + NO_JUSTIFICATION, /* just */ + 0, /* page */ + 0, /* index */ + (int)' ', /* pad */ + A_NORMAL, /* fore */ + A_NORMAL, /* back */ + ALL_FIELD_OPTS, /* opts */ + (FIELD *)0, /* snext */ + (FIELD *)0, /* sprev */ + (FIELD *)0, /* link */ + (FORM *)0, /* form */ + (FIELDTYPE *)0, /* type */ + (char *)0, /* arg */ + (char *)0, /* buf */ + (char *)0 /* usrptr */ +}; + +FIELD *_nc_Default_Field = &default_field; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : TypeArgument *_nc_Make_Argument( +| const FIELDTYPE *typ, +| va_list *ap, +| int *err ) +| +| Description : Create an argument structure for the specified type. +| Use the type-dependent argument list to construct +| it. +| +| Return Values : Pointer to argument structure. Maybe NULL. +| In case of an error in *err an errorcounter is increased. ++--------------------------------------------------------------------------*/ +TypeArgument* +_nc_Make_Argument(const FIELDTYPE *typ, va_list *ap, int *err) +{ + TypeArgument *res = (TypeArgument *)0; + TypeArgument *p; + + if (typ && (typ->status & _HAS_ARGS)) + { + assert(err && ap); + if (typ->status & _LINKED_TYPE) + { + p = (TypeArgument *)malloc(sizeof(TypeArgument)); + if (p) + { + p->left = _nc_Make_Argument(typ->left ,ap,err); + p->right = _nc_Make_Argument(typ->right,ap,err); + return p; + } + else + *err += 1; + } else + { + assert(typ->makearg != 0); + if ( !(res=(TypeArgument *)typ->makearg(ap)) ) + *err += 1; + } + } + return res; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : TypeArgument *_nc_Copy_Argument(const FIELDTYPE *typ, +| const TypeArgument *argp, +| int *err ) +| +| Description : Create a copy of an argument structure for the specified +| type. +| +| Return Values : Pointer to argument structure. Maybe NULL. +| In case of an error in *err an errorcounter is increased. ++--------------------------------------------------------------------------*/ +TypeArgument* +_nc_Copy_Argument(const FIELDTYPE *typ, + const TypeArgument *argp, int *err) +{ + TypeArgument *res = (TypeArgument *)0; + TypeArgument *p; + + if ( typ && (typ->status & _HAS_ARGS) ) + { + assert(err && argp); + if (typ->status & _LINKED_TYPE) + { + p = (TypeArgument *)malloc(sizeof(TypeArgument)); + if (p) + { + p->left = _nc_Copy_Argument(typ,argp->left ,err); + p->right = _nc_Copy_Argument(typ,argp->right,err); + return p; + } + *err += 1; + } + else + { + if (typ->copyarg) + { + if (!(res = (TypeArgument *)(typ->copyarg((const void *)argp)))) + *err += 1; + } + else + res = (TypeArgument *)argp; + } + } + return res; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : void _nc_Free_Argument(const FIELDTYPE *typ, +| TypeArgument * argp ) +| +| Description : Release memory associated with the argument structure +| for the given fieldtype. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +void +_nc_Free_Argument(const FIELDTYPE * typ, TypeArgument * argp) +{ + if (!typ || !(typ->status & _HAS_ARGS)) + return; + + if (typ->status & _LINKED_TYPE) + { + assert(argp != 0); + _nc_Free_Argument(typ->left ,argp->left ); + _nc_Free_Argument(typ->right,argp->right); + free(argp); + } + else + { + if (typ->freearg) + typ->freearg((void *)argp); + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : bool _nc_Copy_Type( FIELD *dst, FIELD const *src ) +| +| Description : Copy argument structure of field src to field dst +| +| Return Values : TRUE - copy worked +| FALSE - error occurred ++--------------------------------------------------------------------------*/ +bool +_nc_Copy_Type(FIELD *dst, FIELD const *src) +{ + int err = 0; + + assert(dst && src); + + dst->type = src->type; + dst->arg = (void *)_nc_Copy_Argument(src->type,(TypeArgument *)(src->arg),&err); + + if (err) + { + _nc_Free_Argument(dst->type,(TypeArgument *)(dst->arg)); + dst->type = (FIELDTYPE *)0; + dst->arg = (void *)0; + return FALSE; + } + else + { + if (dst->type) + dst->type->ref++; + return TRUE; + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : void _nc_Free_Type( FIELD *field ) +| +| Description : Release Argument structure for this field +| +| Return Values : - ++--------------------------------------------------------------------------*/ +void +_nc_Free_Type(FIELD *field) +{ + assert(field != 0); + if (field->type) + field->type->ref--; + _nc_Free_Argument(field->type,(TypeArgument *)(field->arg)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FIELD *new_field( int rows, int cols, +| int frow, int fcol, +| int nrow, int nbuf ) +| +| Description : Create a new field with this many 'rows' and 'cols', +| starting at 'frow/fcol' in the subwindow of the form. +| Allocate 'nrow' off-screen rows and 'nbuf' additional +| buffers. If an error occurs, errno is set to +| +| E_BAD_ARGUMENT - invalid argument +| E_SYSTEM_ERROR - system error +| +| Return Values : Pointer to the new field or NULL if failure. ++--------------------------------------------------------------------------*/ +FIELD *new_field(int rows, int cols, int frow, int fcol, int nrow, int nbuf) +{ + FIELD *New_Field = (FIELD *)0; + int err = E_BAD_ARGUMENT; + + if (rows>0 && + cols>0 && + frow>=0 && + fcol>=0 && + nrow>=0 && + nbuf>=0 && + ((err = E_SYSTEM_ERROR) != 0) && /* trick: this resets the default error */ + (New_Field=(FIELD *)malloc(sizeof(FIELD))) ) + { + *New_Field = default_field; + New_Field->rows = rows; + New_Field->cols = cols; + New_Field->drows = rows + nrow; + New_Field->dcols = cols; + New_Field->frow = frow; + New_Field->fcol = fcol; + New_Field->nrow = nrow; + New_Field->nbuf = nbuf; + New_Field->link = New_Field; + + if (_nc_Copy_Type(New_Field,&default_field)) + { + size_t len; + + len = Total_Buffer_Size(New_Field); + if ((New_Field->buf = (char *)malloc(len))) + { + /* Prefill buffers with blanks and insert terminating zeroes + between buffers */ + int i; + + memset(New_Field->buf,' ',len); + for(i=0;i<=New_Field->nbuf;i++) + { + New_Field->buf[(New_Field->drows*New_Field->cols+1)*(i+1)-1] + = '\0'; + } + return New_Field; + } + } + } + + if (New_Field) + free_field(New_Field); + + SET_ERROR( err ); + return (FIELD *)0; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int free_field( FIELD *field ) +| +| Description : Frees the storage allocated for the field. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid field pointer +| E_CONNECTED - field is connected ++--------------------------------------------------------------------------*/ +int free_field(FIELD * field) +{ + if (!field) + RETURN(E_BAD_ARGUMENT); + + if (field->form) + RETURN(E_CONNECTED); + + if (field == field->link) + { + if (field->buf) + free(field->buf); + } + else + { + FIELD *f; + + for(f=field;f->link != field;f = f->link) + {} + f->link = field->link; + } + _nc_Free_Type(field); + free(field); + RETURN(E_OK); +} + +/* fld_def.c ends here */ diff --git a/Source/CursesDialog/form/fld_dup.c b/Source/CursesDialog/form/fld_dup.c new file mode 100644 index 0000000..1c5301d --- /dev/null +++ b/Source/CursesDialog/form/fld_dup.c @@ -0,0 +1,97 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FIELD *dup_field(FIELD *field, int frow, int fcol) +| +| Description : Duplicates the field at the specified position. All +| field attributes and the buffers are copied. +| If an error occurs, errno is set to +| +| E_BAD_ARGUMENT - invalid argument +| E_SYSTEM_ERROR - system error +| +| Return Values : Pointer to the new field or NULL if failure ++--------------------------------------------------------------------------*/ +FIELD *dup_field(FIELD * field, int frow, int fcol) +{ + FIELD *New_Field = (FIELD *)0; + int err = E_BAD_ARGUMENT; + + if (field && (frow>=0) && (fcol>=0) && + ((err=E_SYSTEM_ERROR) != 0) && /* trick : this resets the default error */ + (New_Field=(FIELD *)malloc(sizeof(FIELD))) ) + { + *New_Field = *_nc_Default_Field; + New_Field->frow = frow; + New_Field->fcol = fcol; + New_Field->link = New_Field; + New_Field->rows = field->rows; + New_Field->cols = field->cols; + New_Field->nrow = field->nrow; + New_Field->drows = field->drows; + New_Field->dcols = field->dcols; + New_Field->maxgrow = field->maxgrow; + New_Field->nbuf = field->nbuf; + New_Field->just = field->just; + New_Field->fore = field->fore; + New_Field->back = field->back; + New_Field->pad = field->pad; + New_Field->opts = field->opts; + New_Field->usrptr = field->usrptr; + + if (_nc_Copy_Type(New_Field,field)) + { + size_t len; + + len = Total_Buffer_Size(New_Field); + if ( (New_Field->buf=(char *)malloc(len)) ) + { + memcpy(New_Field->buf,field->buf,len); + return New_Field; + } + } + } + + if (New_Field) + free_field(New_Field); + + SET_ERROR(err); + return (FIELD *)0; +} + +/* fld_dup.c ends here */ diff --git a/Source/CursesDialog/form/fld_ftchoice.c b/Source/CursesDialog/form/fld_ftchoice.c new file mode 100644 index 0000000..bb37073 --- /dev/null +++ b/Source/CursesDialog/form/fld_ftchoice.c @@ -0,0 +1,62 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_fieldtype_choice( +| FIELDTYPE *typ, +| bool (* const next_choice)(FIELD *,const void *), +| bool (* const prev_choice)(FIELD *,const void *)) +| +| Description : Define implementation of enumeration requests. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid arguments ++--------------------------------------------------------------------------*/ +int set_fieldtype_choice(FIELDTYPE * typ, + bool (* const next_choice) (FIELD *,const void *), + bool (* const prev_choice) (FIELD *,const void *)) +{ + if ( !typ || !next_choice || !prev_choice ) + RETURN(E_BAD_ARGUMENT); + + typ->status |= _HAS_CHOICE; + typ->next = next_choice; + typ->prev = prev_choice; + RETURN(E_OK); +} + +/* fld_ftchoice.c ends here */ diff --git a/Source/CursesDialog/form/fld_ftlink.c b/Source/CursesDialog/form/fld_ftlink.c new file mode 100644 index 0000000..e98a4ca --- /dev/null +++ b/Source/CursesDialog/form/fld_ftlink.c @@ -0,0 +1,83 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FIELDTYPE *link_fieldtype( +| FIELDTYPE *type1, +| FIELDTYPE *type2) +| +| Description : Create a new fieldtype built from the two given types. +| They are connected by an logical 'OR'. +| If an error occurs, errno is set to +| E_BAD_ARGUMENT - invalid arguments +| E_SYSTEM_ERROR - system error (no memory) +| +| Return Values : Fieldtype pointer or NULL if error occurred. ++--------------------------------------------------------------------------*/ +FIELDTYPE *link_fieldtype(FIELDTYPE * type1, FIELDTYPE * type2) +{ + FIELDTYPE *nftyp = (FIELDTYPE *)0; + + if ( type1 && type2 ) + { + nftyp = (FIELDTYPE *)malloc(sizeof(FIELDTYPE)); + if (nftyp) + { + *nftyp = *_nc_Default_FieldType; + nftyp->status |= _LINKED_TYPE; + if ((type1->status & _HAS_ARGS) || (type2->status & _HAS_ARGS) ) + nftyp->status |= _HAS_ARGS; + if ((type1->status & _HAS_CHOICE) || (type2->status & _HAS_CHOICE) ) + nftyp->status |= _HAS_CHOICE; + nftyp->left = type1; + nftyp->right = type2; + type1->ref++; + type2->ref++; + } + else + { + SET_ERROR( E_SYSTEM_ERROR ); + } + } + else + { + SET_ERROR( E_BAD_ARGUMENT ); + } + return nftyp; +} + +/* fld_ftlink.c ends here */ diff --git a/Source/CursesDialog/form/fld_info.c b/Source/CursesDialog/form/fld_info.c new file mode 100644 index 0000000..1ba92c8 --- /dev/null +++ b/Source/CursesDialog/form/fld_info.c @@ -0,0 +1,91 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int field_info(const FIELD *field, +| int *rows, int *cols, +| int *frow, int *fcol, +| int *nrow, int *nbuf) +| +| Description : Retrieve infos about the fields creation parameters. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid field pointer ++--------------------------------------------------------------------------*/ +int field_info(const FIELD *field, + int *rows, int *cols, + int *frow, int *fcol, + int *nrow, int *nbuf) +{ + if (!field) + RETURN(E_BAD_ARGUMENT); + + if (rows) *rows = field->rows; + if (cols) *cols = field->cols; + if (frow) *frow = field->frow; + if (fcol) *fcol = field->fcol; + if (nrow) *nrow = field->nrow; + if (nbuf) *nbuf = field->nbuf; + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int dynamic_field_info(const FIELD *field, +| int *drows, int *dcols, +| int *maxgrow) +| +| Description : Retrieve information about a dynamic fields current +| dynamic parameters. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid argument ++--------------------------------------------------------------------------*/ +int dynamic_field_info(const FIELD *field, + int *drows, int *dcols, int *maxgrow) +{ + if (!field) + RETURN(E_BAD_ARGUMENT); + + if (drows) *drows = field->drows; + if (dcols) *dcols = field->dcols; + if (maxgrow) *maxgrow = field->maxgrow; + + RETURN(E_OK); +} + +/* fld_info.c ends here */ diff --git a/Source/CursesDialog/form/fld_just.c b/Source/CursesDialog/form/fld_just.c new file mode 100644 index 0000000..7015654 --- /dev/null +++ b/Source/CursesDialog/form/fld_just.c @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_just(FIELD *field, int just) +| +| Description : Set the fields type of justification. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - one of the arguments was incorrect +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +int set_field_just(FIELD * field, int just) +{ + int res = E_BAD_ARGUMENT; + + if ((just==NO_JUSTIFICATION) || + (just==JUSTIFY_LEFT) || + (just==JUSTIFY_CENTER) || + (just==JUSTIFY_RIGHT) ) + { + Normalize_Field( field ); + if (field->just != just) + { + field->just = just; + res = _nc_Synchronize_Attributes( field ); + } + else + res = E_OK; + } + RETURN(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int field_just( const FIELD *field ) +| +| Description : Retrieve the fields type of justification +| +| Return Values : The justification type. ++--------------------------------------------------------------------------*/ +int field_just(const FIELD * field) +{ + return Normalize_Field( field )->just; +} + +/* fld_just.c ends here */ diff --git a/Source/CursesDialog/form/fld_link.c b/Source/CursesDialog/form/fld_link.c new file mode 100644 index 0000000..164f51b --- /dev/null +++ b/Source/CursesDialog/form/fld_link.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FIELD *link_field(FIELD *field, int frow, int fcol) +| +| Description : Duplicates the field at the specified position. The +| new field shares its buffers with the original one, +| the attributes are independent. +| If an error occurs, errno is set to +| +| E_BAD_ARGUMENT - invalid argument +| E_SYSTEM_ERROR - system error +| +| Return Values : Pointer to the new field or NULL if failure ++--------------------------------------------------------------------------*/ +FIELD *link_field(FIELD * field, int frow, int fcol) +{ + FIELD *New_Field = (FIELD *)0; + int err = E_BAD_ARGUMENT; + + if (field && (frow>=0) && (fcol>=0) && + ((err=E_SYSTEM_ERROR) != 0) && /* trick: this resets the default error */ + (New_Field = (FIELD *)malloc(sizeof(FIELD))) ) + { + *New_Field = *_nc_Default_Field; + New_Field->frow = frow; + New_Field->fcol = fcol; + New_Field->link = field->link; + field->link = New_Field; + New_Field->buf = field->buf; + New_Field->rows = field->rows; + New_Field->cols = field->cols; + New_Field->nrow = field->nrow; + New_Field->nbuf = field->nbuf; + New_Field->drows = field->drows; + New_Field->dcols = field->dcols; + New_Field->maxgrow= field->maxgrow; + New_Field->just = field->just; + New_Field->fore = field->fore; + New_Field->back = field->back; + New_Field->pad = field->pad; + New_Field->opts = field->opts; + New_Field->usrptr = field->usrptr; + if (_nc_Copy_Type(New_Field,field)) + return New_Field; + } + + if (New_Field) + free_field(New_Field); + + SET_ERROR( err ); + return (FIELD *)0; +} + +/* fld_link.c ends here */ diff --git a/Source/CursesDialog/form/fld_max.c b/Source/CursesDialog/form/fld_max.c new file mode 100644 index 0000000..cca8dc5 --- /dev/null +++ b/Source/CursesDialog/form/fld_max.c @@ -0,0 +1,74 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_max_field(FIELD *field, int maxgrow) +| +| Description : Set the maximum growth for a dynamic field. If maxgrow=0 +| the field may grow to any possible size. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid argument ++--------------------------------------------------------------------------*/ +int set_max_field(FIELD *field, int maxgrow) +{ + if (!field || (maxgrow<0)) + RETURN(E_BAD_ARGUMENT); + else + { + bool single_line_field = Single_Line_Field(field); + + if (maxgrow>0) + { + if (( single_line_field && (maxgrow < field->dcols)) || + (!single_line_field && (maxgrow < field->drows))) + RETURN(E_BAD_ARGUMENT); + } + field->maxgrow = maxgrow; + field->status &= ~_MAY_GROW; + if (!(field->opts & O_STATIC)) + { + if ((maxgrow==0) || + ( single_line_field && (field->dcols < maxgrow)) || + (!single_line_field && (field->drows < maxgrow))) + field->status |= _MAY_GROW; + } + } + RETURN(E_OK); +} + +/* fld_max.c ends here */ diff --git a/Source/CursesDialog/form/fld_move.c b/Source/CursesDialog/form/fld_move.c new file mode 100644 index 0000000..2293477 --- /dev/null +++ b/Source/CursesDialog/form/fld_move.c @@ -0,0 +1,62 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int move_field(FIELD *field,int frow, int fcol) +| +| Description : Moves the disconnected field to the new location in +| the forms subwindow. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid argument passed +| E_CONNECTED - field is connected ++--------------------------------------------------------------------------*/ +int move_field(FIELD *field, int frow, int fcol) +{ + if ( !field || (frow<0) || (fcol<0) ) + RETURN(E_BAD_ARGUMENT); + + if (field->form) + RETURN(E_CONNECTED); + + field->frow = frow; + field->fcol = fcol; + RETURN(E_OK); +} + +/* fld_move.c ends here */ + diff --git a/Source/CursesDialog/form/fld_newftyp.c b/Source/CursesDialog/form/fld_newftyp.c new file mode 100644 index 0000000..b839f19 --- /dev/null +++ b/Source/CursesDialog/form/fld_newftyp.c @@ -0,0 +1,125 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +static FIELDTYPE const default_fieldtype = { + 0, /* status */ + 0L, /* reference count */ + (FIELDTYPE *)0, /* pointer to left operand */ + (FIELDTYPE *)0, /* pointer to right operand */ + NULL, /* makearg function */ + NULL, /* copyarg function */ + NULL, /* freearg function */ + NULL, /* field validation function */ + NULL, /* Character check function */ + NULL, /* enumerate next function */ + NULL /* enumerate previous function */ +}; + +const FIELDTYPE* _nc_Default_FieldType = &default_fieldtype; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FIELDTYPE *new_fieldtype( +| bool (* const field_check)(FIELD *,const void *), +| bool (* const char_check) (int, const void *) ) +| +| Description : Create a new fieldtype. The application programmer must +| write a field_check and a char_check function and give +| them as input to this call. +| If an error occurs, errno is set to +| E_BAD_ARGUMENT - invalid arguments +| E_SYSTEM_ERROR - system error (no memory) +| +| Return Values : Fieldtype pointer or NULL if error occurred ++--------------------------------------------------------------------------*/ +FIELDTYPE *new_fieldtype( + bool (* const field_check)(FIELD *,const void *), + bool (* const char_check) (int,const void *) ) +{ + FIELDTYPE *nftyp = (FIELDTYPE *)0; + + if ( (field_check) || (char_check) ) + { + nftyp = (FIELDTYPE *)malloc(sizeof(FIELDTYPE)); + if (nftyp) + { + *nftyp = default_fieldtype; + nftyp->fcheck = field_check; + nftyp->ccheck = char_check; + } + else + { + SET_ERROR( E_SYSTEM_ERROR ); + } + } + else + { + SET_ERROR( E_BAD_ARGUMENT ); + } + return nftyp; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int free_fieldtype(FIELDTYPE *typ) +| +| Description : Release the memory associated with this fieldtype. +| +| Return Values : E_OK - success +| E_CONNECTED - there are fields referencing the type +| E_BAD_ARGUMENT - invalid fieldtype pointer ++--------------------------------------------------------------------------*/ +int free_fieldtype(FIELDTYPE *typ) +{ + if (!typ) + RETURN(E_BAD_ARGUMENT); + + if (typ->ref!=0) + RETURN(E_CONNECTED); + + if (typ->status & _RESIDENT) + RETURN(E_CONNECTED); + + if (typ->status & _LINKED_TYPE) + { + if (typ->left ) typ->left->ref--; + if (typ->right) typ->right->ref--; + } + free(typ); + RETURN(E_OK); +} + +/* fld_newftyp.c ends here */ diff --git a/Source/CursesDialog/form/fld_opts.c b/Source/CursesDialog/form/fld_opts.c new file mode 100644 index 0000000..234634b --- /dev/null +++ b/Source/CursesDialog/form/fld_opts.c @@ -0,0 +1,124 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*---------------------------------------------------------------------------- + Field-Options manipulation routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_opts(FIELD *field, Field_Options opts) +| +| Description : Turns on the named options for this field and turns +| off all the remaining options. +| +| Return Values : E_OK - success +| E_CURRENT - the field is the current field +| E_BAD_ARGUMENT - invalid options +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +int set_field_opts(FIELD * field, Field_Options opts) +{ + int res = E_BAD_ARGUMENT; + opts &= ALL_FIELD_OPTS; + if (!(opts & ~ALL_FIELD_OPTS)) + res = _nc_Synchronize_Options( Normalize_Field(field), opts ); + RETURN(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : Field_Options field_opts(const FIELD *field) +| +| Description : Retrieve the fields options. +| +| Return Values : The options. ++--------------------------------------------------------------------------*/ +Field_Options field_opts(const FIELD * field) +{ + return ALL_FIELD_OPTS & Normalize_Field( field )->opts; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int field_opts_on(FIELD *field, Field_Options opts) +| +| Description : Turns on the named options for this field and all the +| remaining options are unchanged. +| +| Return Values : E_OK - success +| E_CURRENT - the field is the current field +| E_BAD_ARGUMENT - invalid options +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +int field_opts_on(FIELD * field, Field_Options opts) +{ + int res = E_BAD_ARGUMENT; + + opts &= ALL_FIELD_OPTS; + if (!(opts & ~ALL_FIELD_OPTS)) + { + Normalize_Field( field ); + res = _nc_Synchronize_Options( field, field->opts | opts ); + } + RETURN(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int field_opts_off(FIELD *field, Field_Options opts) +| +| Description : Turns off the named options for this field and all the +| remaining options are unchanged. +| +| Return Values : E_OK - success +| E_CURRENT - the field is the current field +| E_BAD_ARGUMENT - invalid options +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +int field_opts_off(FIELD * field, Field_Options opts) +{ + int res = E_BAD_ARGUMENT; + + opts &= ALL_FIELD_OPTS; + if (!(opts & ~ALL_FIELD_OPTS)) + { + Normalize_Field( field ); + res = _nc_Synchronize_Options( field, field->opts & ~opts ); + } + RETURN(res); +} + +/* fld_opts.c ends here */ diff --git a/Source/CursesDialog/form/fld_pad.c b/Source/CursesDialog/form/fld_pad.c new file mode 100644 index 0000000..4598340 --- /dev/null +++ b/Source/CursesDialog/form/fld_pad.c @@ -0,0 +1,78 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_pad(FIELD *field, int ch) +| +| Description : Set the pad character used to fill the field. This must +| be a printable character. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid field pointer or pad character +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +int set_field_pad(FIELD * field, int ch) +{ + int res = E_BAD_ARGUMENT; + + Normalize_Field( field ); + if (isprint((unsigned char)ch)) + { + if (field->pad != ch) + { + field->pad = ch; + res = _nc_Synchronize_Attributes( field ); + } + else + res = E_OK; + } + RETURN(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int field_pad(const FIELD *field) +| +| Description : Retrieve the fields pad character. +| +| Return Values : The pad character. ++--------------------------------------------------------------------------*/ +int field_pad(const FIELD * field) +{ + return Normalize_Field( field )->pad; +} + +/* fld_pad.c ends here */ diff --git a/Source/CursesDialog/form/fld_page.c b/Source/CursesDialog/form/fld_page.c new file mode 100644 index 0000000..408e712 --- /dev/null +++ b/Source/CursesDialog/form/fld_page.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_new_page(FIELD *field, bool new_page_flag) +| +| Description : Marks the field as the beginning of a new page of +| the form. +| +| Return Values : E_OK - success +| E_CONNECTED - field is connected ++--------------------------------------------------------------------------*/ +int set_new_page(FIELD * field, bool new_page_flag) +{ + Normalize_Field(field); + if (field->form) + RETURN(E_CONNECTED); + + if (new_page_flag) + field->status |= _NEWPAGE; + else + field->status &= ~_NEWPAGE; + + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : bool new_page(const FIELD *field) +| +| Description : Retrieve the info whether or not the field starts a +| new page on the form. +| +| Return Values : TRUE - field starts a new page +| FALSE - field doesn't start a new page ++--------------------------------------------------------------------------*/ +bool new_page(const FIELD * field) +{ + return (Normalize_Field(field)->status & _NEWPAGE) ? TRUE : FALSE; +} + +/* fld_page.c ends here */ diff --git a/Source/CursesDialog/form/fld_stat.c b/Source/CursesDialog/form/fld_stat.c new file mode 100644 index 0000000..ee6831b --- /dev/null +++ b/Source/CursesDialog/form/fld_stat.c @@ -0,0 +1,73 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_status(FIELD *field, bool status) +| +| Description : Set or clear the 'changed' indication flag for that +| fields primary buffer. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +int set_field_status(FIELD * field, bool status) +{ + Normalize_Field( field ); + + if (status) + field->status |= _CHANGED; + else + field->status &= ~_CHANGED; + + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : bool field_status(const FIELD *field) +| +| Description : Retrieve the value of the 'changed' indication flag +| for that fields primary buffer. +| +| Return Values : TRUE - buffer has been changed +| FALSE - buffer has not been changed ++--------------------------------------------------------------------------*/ +bool field_status(const FIELD * field) +{ + return ((Normalize_Field(field)->status & _CHANGED) ? TRUE : FALSE); +} + +/* fld_stat.c ends here */ diff --git a/Source/CursesDialog/form/fld_type.c b/Source/CursesDialog/form/fld_type.c new file mode 100644 index 0000000..6c9def2 --- /dev/null +++ b/Source/CursesDialog/form/fld_type.c @@ -0,0 +1,51 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FIELDTYPE *field_type(const FIELD *field) +| +| Description : Retrieve the associated fieldtype for this field. +| +| Return Values : Pointer to fieldtype of NULL if none is defined. ++--------------------------------------------------------------------------*/ +FIELDTYPE *field_type(const FIELD * field) +{ + return Normalize_Field(field)->type; +} + +/* fld_type.c ends here */ diff --git a/Source/CursesDialog/form/fld_user.c b/Source/CursesDialog/form/fld_user.c new file mode 100644 index 0000000..3287b5b --- /dev/null +++ b/Source/CursesDialog/form/fld_user.c @@ -0,0 +1,67 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_userptr(FIELD *field, void *usrptr) +| +| Description : Set the pointer that is reserved in any field to store +| application relevant information +| +| Return Values : E_OK - on success ++--------------------------------------------------------------------------*/ +int set_field_userptr(FIELD * field, void *usrptr) +{ + Normalize_Field( field )->usrptr = usrptr; + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : void *field_userptr(const FIELD *field) +| +| Description : Return the pointer that is reserved in any field to +| store application relevant information. +| +| Return Values : Value of pointer. If no such pointer has been set, +| NULL is returned ++--------------------------------------------------------------------------*/ +void *field_userptr(const FIELD *field) +{ + return Normalize_Field( field )->usrptr; +} + +/* fld_user.c ends here */ diff --git a/Source/CursesDialog/form/form.h b/Source/CursesDialog/form/form.h new file mode 100644 index 0000000..39ed75a --- /dev/null +++ b/Source/CursesDialog/form/form.h @@ -0,0 +1,407 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#ifndef FORM_H +#define FORM_H + +#include "cmFormConfigure.h" + +/* figure out which curses.h to include */ +# if defined(CURSES_HAVE_NCURSES_H) +# include <ncurses.h> +# elif defined(CURSES_HAVE_NCURSES_NCURSES_H) +# include <ncurses/ncurses.h> +# elif defined(CURSES_HAVE_NCURSES_CURSES_H) +# include <ncurses/curses.h> +# else +# if defined(__hpux) +# if defined(_XOPEN_SOURCE_EXTENDED) +# define HAVE__XOPEN_SOURCE_EXTENDED +# else +# define _XOPEN_SOURCE_EXTENDED +# endif +# endif +# include <curses.h> +# if defined(__hpux) && !defined(HAVE__XOPEN_SOURCE_EXTENDED) +# undef _XOPEN_SOURCE_EXTENDED +# endif +# endif + +#include <eti.h> +#include <stdarg.h> + +#ifdef __cplusplus + extern "C" { +#endif + +typedef int Form_Options; +typedef int Field_Options; + + /********** + * _PAGE * + **********/ + +typedef struct { + short pmin; /* index of first field on page */ + short pmax; /* index of last field on page */ + short smin; /* index of top leftmost field on page */ + short smax; /* index of bottom rightmost field on page */ +} _PAGE; + + /********** + * FIELD * + **********/ + +typedef struct fieldnode { + unsigned short status; /* flags */ + short rows; /* size in rows */ + short cols; /* size in cols */ + short frow; /* first row */ + short fcol; /* first col */ + int drows; /* dynamic rows */ + int dcols; /* dynamic cols */ + int maxgrow; /* maximum field growth */ + int nrow; /* offscreen rows */ + short nbuf; /* additional buffers */ + short just; /* justification */ + short page; /* page on form */ + short index; /* into form -> field */ + int pad; /* pad character */ + chtype fore; /* foreground attribute */ + chtype back; /* background attribute */ + Field_Options opts; /* options */ + struct fieldnode * snext; /* sorted order pointer */ + struct fieldnode * sprev; /* sorted order pointer */ + struct fieldnode * link; /* linked field chain */ + struct formnode * form; /* containing form */ + struct typenode * type; /* field type */ + void * arg; /* argument for type */ + char * buf; /* field buffers */ + void * usrptr; /* user pointer */ +} FIELD; + + /************** + * FIELDTYPE * + **************/ + +typedef struct typenode { + unsigned short status; /* flags */ + long ref; /* reference count */ + struct typenode * left; /* ptr to operand for | */ + struct typenode * right; /* ptr to operand for | */ + + void* (*makearg)(va_list *); /* make fieldtype arg */ + void* (*copyarg)(const void *); /* copy fieldtype arg */ + void (*freearg)(void *); /* free fieldtype arg */ + + bool (*fcheck)(FIELD *,const void *); /* field validation */ + bool (*ccheck)(int,const void *); /* character validation */ + + bool (*next)(FIELD *,const void *); /* enumerate next value */ + bool (*prev)(FIELD *,const void *); /* enumerate prev value */ + +} FIELDTYPE; + + /********* + * FORM * + *********/ + +typedef struct formnode { + unsigned short status; /* flags */ + short rows; /* size in rows */ + short cols; /* size in cols */ + int currow; /* current row in field window*/ + int curcol; /* current col in field window*/ + int toprow; /* in scrollable field window */ + int begincol; /* in horiz. scrollable field */ + short maxfield; /* number of fields */ + short maxpage; /* number of pages */ + short curpage; /* index into page */ + Form_Options opts; /* options */ + WINDOW * win; /* window */ + WINDOW * sub; /* subwindow */ + WINDOW * w; /* window for current field */ + FIELD ** field; /* field [maxfield] */ + FIELD * current; /* current field */ + _PAGE * page; /* page [maxpage] */ + void * usrptr; /* user pointer */ + + void (*forminit)(struct formnode *); + void (*formterm)(struct formnode *); + void (*fieldinit)(struct formnode *); + void (*fieldterm)(struct formnode *); + +} FORM; + +typedef void (*Form_Hook)(FORM *); + + /*************************** + * miscellaneous #defines * + ***************************/ + +/* field justification */ +#define NO_JUSTIFICATION (0) +#define JUSTIFY_LEFT (1) +#define JUSTIFY_CENTER (2) +#define JUSTIFY_RIGHT (3) + +/* field options */ +#define O_VISIBLE (0x0001) +#define O_ACTIVE (0x0002) +#define O_PUBLIC (0x0004) +#define O_EDIT (0x0008) +#define O_WRAP (0x0010) +#define O_BLANK (0x0020) +#define O_AUTOSKIP (0x0040) +#define O_NULLOK (0x0080) +#define O_PASSOK (0x0100) +#define O_STATIC (0x0200) + +/* form options */ +#define O_NL_OVERLOAD (0x0001) +#define O_BS_OVERLOAD (0x0002) + +/* form driver commands */ +#define REQ_NEXT_PAGE (KEY_MAX + 1) /* move to next page */ +#define REQ_PREV_PAGE (KEY_MAX + 2) /* move to previous page */ +#define REQ_FIRST_PAGE (KEY_MAX + 3) /* move to first page */ +#define REQ_LAST_PAGE (KEY_MAX + 4) /* move to last page */ + +#define REQ_NEXT_FIELD (KEY_MAX + 5) /* move to next field */ +#define REQ_PREV_FIELD (KEY_MAX + 6) /* move to previous field */ +#define REQ_FIRST_FIELD (KEY_MAX + 7) /* move to first field */ +#define REQ_LAST_FIELD (KEY_MAX + 8) /* move to last field */ +#define REQ_SNEXT_FIELD (KEY_MAX + 9) /* move to sorted next field */ +#define REQ_SPREV_FIELD (KEY_MAX + 10) /* move to sorted prev field */ +#define REQ_SFIRST_FIELD (KEY_MAX + 11) /* move to sorted first field */ +#define REQ_SLAST_FIELD (KEY_MAX + 12) /* move to sorted last field */ +#define REQ_LEFT_FIELD (KEY_MAX + 13) /* move to left to field */ +#define REQ_RIGHT_FIELD (KEY_MAX + 14) /* move to right to field */ +#define REQ_UP_FIELD (KEY_MAX + 15) /* move to up to field */ +#define REQ_DOWN_FIELD (KEY_MAX + 16) /* move to down to field */ + +#define REQ_NEXT_CHAR (KEY_MAX + 17) /* move to next char in field */ +#define REQ_PREV_CHAR (KEY_MAX + 18) /* move to prev char in field */ +#define REQ_NEXT_LINE (KEY_MAX + 19) /* move to next line in field */ +#define REQ_PREV_LINE (KEY_MAX + 20) /* move to prev line in field */ +#define REQ_NEXT_WORD (KEY_MAX + 21) /* move to next word in field */ +#define REQ_PREV_WORD (KEY_MAX + 22) /* move to prev word in field */ +#define REQ_BEG_FIELD (KEY_MAX + 23) /* move to first char in field */ +#define REQ_END_FIELD (KEY_MAX + 24) /* move after last char in fld */ +#define REQ_BEG_LINE (KEY_MAX + 25) /* move to beginning of line */ +#define REQ_END_LINE (KEY_MAX + 26) /* move after last char in line */ +#define REQ_LEFT_CHAR (KEY_MAX + 27) /* move left in field */ +#define REQ_RIGHT_CHAR (KEY_MAX + 28) /* move right in field */ +#define REQ_UP_CHAR (KEY_MAX + 29) /* move up in field */ +#define REQ_DOWN_CHAR (KEY_MAX + 30) /* move down in field */ + +#define REQ_NEW_LINE (KEY_MAX + 31) /* insert/overlay new line */ +#define REQ_INS_CHAR (KEY_MAX + 32) /* insert blank char at cursor */ +#define REQ_INS_LINE (KEY_MAX + 33) /* insert blank line at cursor */ +#define REQ_DEL_CHAR (KEY_MAX + 34) /* delete char at cursor */ +#define REQ_DEL_PREV (KEY_MAX + 35) /* delete char before cursor */ +#define REQ_DEL_LINE (KEY_MAX + 36) /* delete line at cursor */ +#define REQ_DEL_WORD (KEY_MAX + 37) /* delete line at cursor */ +#define REQ_CLR_EOL (KEY_MAX + 38) /* clear to end of line */ +#define REQ_CLR_EOF (KEY_MAX + 39) /* clear to end of field */ +#define REQ_CLR_FIELD (KEY_MAX + 40) /* clear entire field */ +#define REQ_OVL_MODE (KEY_MAX + 41) /* begin overlay mode */ +#define REQ_INS_MODE (KEY_MAX + 42) /* begin insert mode */ +#define REQ_SCR_FLINE (KEY_MAX + 43) /* scroll field forward a line */ +#define REQ_SCR_BLINE (KEY_MAX + 44) /* scroll field backward a line */ +#define REQ_SCR_FPAGE (KEY_MAX + 45) /* scroll field forward a page */ +#define REQ_SCR_BPAGE (KEY_MAX + 46) /* scroll field backward a page */ +#define REQ_SCR_FHPAGE (KEY_MAX + 47) /* scroll field forward half page */ +#define REQ_SCR_BHPAGE (KEY_MAX + 48) /* scroll field backward half page */ +#define REQ_SCR_FCHAR (KEY_MAX + 49) /* horizontal scroll char */ +#define REQ_SCR_BCHAR (KEY_MAX + 50) /* horizontal scroll char */ +#define REQ_SCR_HFLINE (KEY_MAX + 51) /* horizontal scroll line */ +#define REQ_SCR_HBLINE (KEY_MAX + 52) /* horizontal scroll line */ +#define REQ_SCR_HFHALF (KEY_MAX + 53) /* horizontal scroll half line */ +#define REQ_SCR_HBHALF (KEY_MAX + 54) /* horizontal scroll half line */ + +#define REQ_VALIDATION (KEY_MAX + 55) /* validate field */ +#define REQ_NEXT_CHOICE (KEY_MAX + 56) /* display next field choice */ +#define REQ_PREV_CHOICE (KEY_MAX + 57) /* display prev field choice */ + +#define MIN_FORM_COMMAND (KEY_MAX + 1) /* used by form_driver */ +#define MAX_FORM_COMMAND (KEY_MAX + 57) /* used by form_driver */ + +#if defined(MAX_COMMAND) +# if (MAX_FORM_COMMAND > MAX_COMMAND) +# error Something is wrong -- MAX_FORM_COMMAND is greater than MAX_COMMAND +# elif (MAX_COMMAND != (KEY_MAX + 128)) +# error Something is wrong -- MAX_COMMAND is already inconsistently defined. +# endif +#else +# define MAX_COMMAND (KEY_MAX + 128) +#endif + + /************************* + * standard field types * + *************************/ +extern FIELDTYPE *TYPE_ALPHA, + *TYPE_ALNUM, + *TYPE_ENUM, + *TYPE_INTEGER, + *TYPE_NUMERIC, + *TYPE_REGEXP; + + /************************************ + * built-in additional field types * + * They are not defined in SVr4 * + ************************************/ +extern FIELDTYPE *TYPE_IPV4; /* Internet IP Version 4 address */ + + /*********************** + * Default objects * + ***********************/ +extern FORM *_nc_Default_Form; +extern FIELD *_nc_Default_Field; + + + /*********************** + * FIELDTYPE routines * + ***********************/ +extern FIELDTYPE + *new_fieldtype( + bool (* const field_check)(FIELD *,const void *), + bool (* const char_check)(int,const void *)), + *link_fieldtype(FIELDTYPE *,FIELDTYPE *); + +extern int free_fieldtype(FIELDTYPE *), + set_fieldtype_choice (FIELDTYPE *, + bool (* const next_choice)(FIELD *,const void *), + bool (* const prev_choice)(FIELD *,const void *)); + + /******************* + * FIELD routines * + *******************/ +extern FIELD *new_field(int,int,int,int,int,int), + *dup_field(FIELD *,int,int), + *link_field(FIELD *,int,int); + +extern int free_field(FIELD *), + field_info(const FIELD *,int *,int *,int *,int *,int *,int *), + dynamic_field_info(const FIELD *,int *,int *,int *), + set_max_field( FIELD *,int), + move_field(FIELD *,int,int), + set_field_type(FIELD *,FIELDTYPE *,...), + set_new_page(FIELD *,bool), + set_field_just(FIELD *,int), + field_just(const FIELD *), + set_field_fore(FIELD *,chtype), + set_field_back(FIELD *,chtype), + set_field_pad(FIELD *,int), + field_pad(const FIELD *), + set_field_buffer(FIELD *,int,const char *), + set_field_status(FIELD *,bool), + set_field_userptr(FIELD *, void *), + set_field_opts(FIELD *,Field_Options), + field_opts_on(FIELD *,Field_Options), + field_opts_off(FIELD *,Field_Options); + +extern chtype field_fore(const FIELD *), + field_back(const FIELD *); + +extern bool new_page(const FIELD *), + field_status(const FIELD *); + +extern void *field_arg(const FIELD *); + +extern void *field_userptr(const FIELD *); + +extern FIELDTYPE + *field_type(const FIELD *); + +extern char* field_buffer(const FIELD *,int); + +extern Field_Options + field_opts(const FIELD *); + + /****************** + * FORM routines * + ******************/ +extern FORM *new_form(FIELD **); + +extern FIELD **form_fields(const FORM *), + *current_field(const FORM *); + +extern WINDOW *form_win(const FORM *), + *form_sub(const FORM *); + +extern Form_Hook + form_init(const FORM *), + form_term(const FORM *), + field_init(const FORM *), + field_term(const FORM *); + +extern int free_form(FORM *), + set_form_fields(FORM *,FIELD **), + field_count(const FORM *), + set_form_win(FORM *,WINDOW *), + set_form_sub(FORM *,WINDOW *), + set_current_field(FORM *,FIELD *), + field_index(const FIELD *), + set_form_page(FORM *,int), + form_page(const FORM *), + scale_form(const FORM *,int *,int *), + set_form_init(FORM *,Form_Hook), + set_form_term(FORM *,Form_Hook), + set_field_init(FORM *,Form_Hook), + set_field_term(FORM *,Form_Hook), + post_form(FORM *), + unpost_form(FORM *), + pos_form_cursor(FORM *), + form_driver(FORM *,int), + set_form_userptr(FORM *,void *), + set_form_opts(FORM *,Form_Options), + form_opts_on(FORM *,Form_Options), + form_opts_off(FORM *,Form_Options), + form_request_by_name(const char *); + +extern const char + *form_request_name(int); + +extern void *form_userptr(const FORM *); + +extern Form_Options + form_opts(const FORM *); + +extern bool data_ahead(const FORM *), + data_behind(const FORM *); + +#ifdef __cplusplus + } +#endif + +#endif /* FORM_H */ diff --git a/Source/CursesDialog/form/form.priv.h b/Source/CursesDialog/form/form.priv.h new file mode 100644 index 0000000..6e00af6 --- /dev/null +++ b/Source/CursesDialog/form/form.priv.h @@ -0,0 +1,128 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "mf_common.h" +#include "form.h" + +/* form status values */ +#define _OVLMODE (0x04) /* Form is in overlay mode */ +#define _WINDOW_MODIFIED (0x10) /* Current field window has been modified */ +#define _FCHECK_REQUIRED (0x20) /* Current field needs validation */ + +/* field status values */ +#define _CHANGED (0x01) /* Field has been changed */ +#define _NEWTOP (0x02) /* Vertical scrolling occurred */ +#define _NEWPAGE (0x04) /* field begins new page of form */ +#define _MAY_GROW (0x08) /* dynamic field may still grow */ + +/* fieldtype status values */ +#define _LINKED_TYPE (0x01) /* Type is a linked type */ +#define _HAS_ARGS (0x02) /* Type has arguments */ +#define _HAS_CHOICE (0x04) /* Type has choice methods */ +#define _RESIDENT (0x08) /* Type is builtin */ + +/* This are the field options required to be a selectable field in field + navigation requests */ +#define O_SELECTABLE (O_ACTIVE | O_VISIBLE) + +/* If form is NULL replace form argument by default-form */ +#define Normalize_Form(form) ((form)=(form)?(form):_nc_Default_Form) + +/* If field is NULL replace field argument by default-field */ +#define Normalize_Field(field) ((field)=(field)?(field):_nc_Default_Field) + +/* Retrieve forms window */ +#define Get_Form_Window(form) \ + ((form)->sub?(form)->sub:((form)->win?(form)->win:stdscr)) + +/* Calculate the size for a single buffer for this field */ +#define Buffer_Length(field) ((field)->drows * (field)->dcols) + +/* Calculate the total size of all buffers for this field */ +#define Total_Buffer_Size(field) \ + ( (Buffer_Length(field) + 1) * (1+(field)->nbuf) ) + +/* Logic to determine whether or not a field is single lined */ +#define Single_Line_Field(field) \ + (((field)->rows + (field)->nrow) == 1) + +/* Logic to determine whether or not a field is selectable */ +#define Field_Is_Selectable(f) (((f)->opts & O_SELECTABLE)==O_SELECTABLE) +#define Field_Is_Not_Selectable(f) (((f)->opts & O_SELECTABLE)!=O_SELECTABLE) + +typedef struct typearg { + struct typearg *left; + struct typearg *right; +} TypeArgument; + +/* This is a dummy request code (normally invalid) to be used internally + with the form_driver() routine to position to the first active field + on the form +*/ +#define FIRST_ACTIVE_MAGIC (-291056) + +#define ALL_FORM_OPTS ( \ + O_NL_OVERLOAD |\ + O_BS_OVERLOAD ) + +#define ALL_FIELD_OPTS ( \ + O_VISIBLE |\ + O_ACTIVE |\ + O_PUBLIC |\ + O_EDIT |\ + O_WRAP |\ + O_BLANK |\ + O_AUTOSKIP|\ + O_NULLOK |\ + O_PASSOK |\ + O_STATIC ) + + +#define C_BLANK ' ' +#define is_blank(c) ((c)==C_BLANK) + +extern const FIELDTYPE* _nc_Default_FieldType; + +extern TypeArgument* _nc_Make_Argument(const FIELDTYPE*,va_list*,int*); +extern TypeArgument *_nc_Copy_Argument(const FIELDTYPE*,const TypeArgument*, int*); +extern void _nc_Free_Argument(const FIELDTYPE*,TypeArgument*); +extern bool _nc_Copy_Type(FIELD*, FIELD const *); +extern void _nc_Free_Type(FIELD *); + +extern int _nc_Synchronize_Attributes(FIELD*); +extern int _nc_Synchronize_Options(FIELD*,Field_Options); +extern int _nc_Set_Form_Page(FORM*,int,FIELD*); +extern int _nc_Refresh_Current_Field(FORM*); +extern FIELD* _nc_First_Active_Field(FORM*); +extern bool _nc_Internal_Validation(FORM*); +extern int _nc_Set_Current_Field(FORM*,FIELD*); +extern int _nc_Position_Form_Cursor(FORM*); diff --git a/Source/CursesDialog/form/frm_cursor.c b/Source/CursesDialog/form/frm_cursor.c new file mode 100644 index 0000000..6c311fe --- /dev/null +++ b/Source/CursesDialog/form/frm_cursor.c @@ -0,0 +1,66 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int pos_form_cursor(FORM * form) +| +| Description : Moves the form window cursor to the location required +| by the form driver to resume form processing. This may +| be needed after the application calls a curses library +| I/O routine that modifies the cursor position. +| +| Return Values : E_OK - Success +| E_SYSTEM_ERROR - System error. +| E_BAD_ARGUMENT - Invalid form pointer +| E_NOT_POSTED - Form is not posted ++--------------------------------------------------------------------------*/ +int pos_form_cursor(FORM * form) +{ + int res; + + if (!form) + res = E_BAD_ARGUMENT; + else + { + if (!(form->status & _POSTED)) + res = E_NOT_POSTED; + else + res = _nc_Position_Form_Cursor(form); + } + RETURN(res); +} + +/* frm_cursor.c ends here */ diff --git a/Source/CursesDialog/form/frm_data.c b/Source/CursesDialog/form/frm_data.c new file mode 100644 index 0000000..fb62ab8 --- /dev/null +++ b/Source/CursesDialog/form/frm_data.c @@ -0,0 +1,183 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +extern int winnstr(WINDOW *, char *, int); + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : bool data_behind(const FORM *form) +| +| Description : Check for off-screen data behind. This is nearly trivial +| becose the begin of a field is fixed. +| +| Return Values : TRUE - there are off-screen data behind +| FALSE - there are no off-screen data behind ++--------------------------------------------------------------------------*/ +bool data_behind(const FORM *form) +{ + bool result = FALSE; + + if (form && (form->status & _POSTED) && form->current) + { + FIELD *field; + + field = form->current; + if (!Single_Line_Field(field)) + { + result = (form->toprow==0) ? FALSE : TRUE; + } + else + { + result = (form->begincol==0) ? FALSE : TRUE; + } + } + return(result); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static char * After_Last_Non_Pad_Position( +| char *buffer, +| int len, +| int pad) +| +| Description : Find the last position in the buffer that doesn't +| contain a padding character. +| +| Return Values : The pointer to this position ++--------------------------------------------------------------------------*/ +INLINE +static char * After_Last_Non_Pad_Position(char *buffer, int len, int pad) +{ + char *end = buffer + len; + + assert(buffer && len>=0); + while ( (buffer < end) && (*(end-1)==pad) ) + end--; + + return end; +} + +#define SMALL_BUFFER_SIZE (80) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : bool data_ahead(const FORM *form) +| +| Description : Check for off-screen data ahead. This is more difficult +| because a dynamic field has a variable end. +| +| Return Values : TRUE - there are off-screen data ahead +| FALSE - there are no off-screen data ahead ++--------------------------------------------------------------------------*/ +bool data_ahead(const FORM *form) +{ + bool result = FALSE; + + if (form && (form->status & _POSTED) && form->current) + { + static char buffer[SMALL_BUFFER_SIZE + 1]; + FIELD *field; + bool large_buffer; + bool cursor_moved = FALSE; + char *bp; + char *found_content; + int pos; + + field = form->current; + assert(form->w != 0); + + large_buffer = (field->cols > SMALL_BUFFER_SIZE); + if (large_buffer) + bp = (char *)malloc((size_t)(field->cols) + 1); + else + bp = buffer; + + assert(bp != 0); + + if (Single_Line_Field(field)) + { + int check_len; + + pos = form->begincol + field->cols; + while (pos < field->dcols) + { + check_len = field->dcols - pos; + if ( check_len >= field->cols ) + check_len = field->cols; + cursor_moved = TRUE; + wmove(form->w,0,pos); + winnstr(form->w,bp,check_len); + found_content = + After_Last_Non_Pad_Position(bp,check_len,field->pad); + if (found_content==bp) + pos += field->cols; + else + { + result = TRUE; + break; + } + } + } + else + { + pos = form->toprow + field->rows; + while (pos < field->drows) + { + cursor_moved = TRUE; + wmove(form->w,pos,0); + pos++; + winnstr(form->w,bp,field->cols); + found_content = + After_Last_Non_Pad_Position(bp,field->cols,field->pad); + if (found_content!=bp) + { + result = TRUE; + break; + } + } + } + + if (large_buffer) + free(bp); + + if (cursor_moved) + wmove(form->w,form->currow,form->curcol); + } + return(result); +} + +/* frm_data.c ends here */ diff --git a/Source/CursesDialog/form/frm_def.c b/Source/CursesDialog/form/frm_def.c new file mode 100644 index 0000000..645b3ba --- /dev/null +++ b/Source/CursesDialog/form/frm_def.c @@ -0,0 +1,376 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/* this can't be readonly */ +static FORM default_form = { + 0, /* status */ + 0, /* rows */ + 0, /* cols */ + 0, /* currow */ + 0, /* curcol */ + 0, /* toprow */ + 0, /* begincol */ + -1, /* maxfield */ + -1, /* maxpage */ + -1, /* curpage */ + ALL_FORM_OPTS, /* opts */ + (WINDOW *)0, /* win */ + (WINDOW *)0, /* sub */ + (WINDOW *)0, /* w */ + (FIELD **)0, /* field */ + (FIELD *)0, /* current */ + (_PAGE *)0, /* page */ + (char *)0, /* usrptr */ + NULL, /* forminit */ + NULL, /* formterm */ + NULL, /* fieldinit */ + NULL /* fieldterm */ +}; + +FORM *_nc_Default_Form = &default_form; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static FIELD *Insert_Field_By_Position( +| FIELD *new_field, +| FIELD *head ) +| +| Description : Insert new_field into sorted fieldlist with head "head" +| and return new head of sorted fieldlist. Sorting +| criteria is (row,column). This is a circular list. +| +| Return Values : New head of sorted fieldlist ++--------------------------------------------------------------------------*/ +static FIELD *Insert_Field_By_Position(FIELD *newfield, FIELD *head) +{ + FIELD *current, *newhead; + + assert(newfield != 0); + + if (!head) + { /* empty list is trivial */ + newhead = newfield->snext = newfield->sprev = newfield; + } + else + { + newhead = current = head; + while((current->frow < newfield->frow) || + ((current->frow==newfield->frow) && + (current->fcol < newfield->fcol)) ) + { + current = current->snext; + if (current==head) + { /* We cycled through. Reset head to indicate that */ + head = (FIELD *)0; + break; + } + } + /* we leave the loop with current pointing to the field after newfield*/ + newfield->snext = current; + newfield->sprev = current->sprev; + newfield->snext->sprev = newfield; + newfield->sprev->snext = newfield; + if (current==head) + newhead = newfield; + } + return(newhead); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Disconnect_Fields(FORM *form) +| +| Description : Break association between form and array of fields. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Disconnect_Fields( FORM * form ) +{ + if (form->field) + { + FIELD **fields; + + for(fields=form->field;*fields;fields++) + { + if (form == (*fields)->form) + (*fields)->form = (FORM *)0; + } + + form->rows = form->cols = 0; + form->maxfield = form->maxpage = -1; + form->field = (FIELD **)0; + if (form->page) + free(form->page); + form->page = (_PAGE *)0; + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Connect_Fields(FORM *form, FIELD **fields) +| +| Description : Set association between form and array of fields. +| +| Return Values : E_OK - no error +| E_CONNECTED - a field is already connected +| E_BAD_ARGUMENT - Invalid form pointer or field array +| E_SYSTEM_ERROR - not enough memory ++--------------------------------------------------------------------------*/ +static int Connect_Fields(FORM * form, FIELD ** fields) +{ + int field_cnt, j; + int page_nr; + int maximum_row_in_field, maximum_col_in_field; + _PAGE *pg; + + assert(form != 0); + + form->field = fields; + form->maxfield = 0; + form->maxpage = 0; + + if (!fields) + RETURN(E_OK); + + page_nr = 0; + /* store formpointer in fields and count pages */ + for(field_cnt=0;fields[field_cnt];field_cnt++) + { + if (fields[field_cnt]->form) + RETURN(E_CONNECTED); + if ( field_cnt==0 || + (fields[field_cnt]->status & _NEWPAGE)) + page_nr++; + fields[field_cnt]->form = form; + } + if (field_cnt==0) + RETURN(E_BAD_ARGUMENT); + + /* allocate page structures */ + if ( (pg = (_PAGE *)malloc(page_nr * sizeof(_PAGE))) != (_PAGE *)0 ) + { + form->page = pg; + } + else + RETURN(E_SYSTEM_ERROR); + + /* Cycle through fields and calculate page boundaries as well as + size of the form */ + for(j=0;j<field_cnt;j++) + { + if (j==0) + pg->pmin = j; + else + { + if (fields[j]->status & _NEWPAGE) + { + pg->pmax = j-1; + pg++; + pg->pmin = j; + } + } + + maximum_row_in_field = fields[j]->frow + fields[j]->rows; + maximum_col_in_field = fields[j]->fcol + fields[j]->cols; + + if (form->rows < maximum_row_in_field) + form->rows = maximum_row_in_field; + if (form->cols < maximum_col_in_field) + form->cols = maximum_col_in_field; + } + + pg->pmax = field_cnt-1; + form->maxfield = field_cnt; + form->maxpage = page_nr; + + /* Sort fields on form pages */ + for(page_nr = 0;page_nr < form->maxpage; page_nr++) + { + FIELD *fld = (FIELD *)0; + for(j = form->page[page_nr].pmin;j <= form->page[page_nr].pmax;j++) + { + fields[j]->index = j; + fields[j]->page = page_nr; + fld = Insert_Field_By_Position(fields[j],fld); + } + form->page[page_nr].smin = fld->index; + form->page[page_nr].smax = fld->sprev->index; + } + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Associate_Fields(FORM *form, FIELD **fields) +| +| Description : Set association between form and array of fields. +| If there are fields, position to first active field. +| +| Return Values : E_OK - success +| any other - error occurred ++--------------------------------------------------------------------------*/ +INLINE static int Associate_Fields(FORM *form, FIELD **fields) +{ + int res = Connect_Fields(form,fields); + if (res == E_OK) + { + if (form->maxpage>0) + { + form->curpage = 0; + form_driver(form,FIRST_ACTIVE_MAGIC); + } + else + { + form->curpage = -1; + form->current = (FIELD *)0; + } + } + return(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FORM *new_form( FIELD **fields ) +| +| Description : Create new form with given array of fields. +| +| Return Values : Pointer to form. NULL if error occurred. ++--------------------------------------------------------------------------*/ +FORM *new_form(FIELD ** fields) +{ + int err = E_SYSTEM_ERROR; + + FORM *form = (FORM *)malloc(sizeof(FORM)); + + if (form) + { + *form = *_nc_Default_Form; + if ((err=Associate_Fields(form,fields))!=E_OK) + { + free_form(form); + form = (FORM *)0; + } + } + + if (!form) + SET_ERROR(err); + + return(form); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int free_form( FORM *form ) +| +| Description : Release internal memory associated with form. +| +| Return Values : E_OK - no error +| E_BAD_ARGUMENT - invalid form pointer +| E_POSTED - form is posted ++--------------------------------------------------------------------------*/ +int free_form(FORM * form) +{ + if ( !form ) + RETURN(E_BAD_ARGUMENT); + + if ( form->status & _POSTED) + RETURN(E_POSTED); + + Disconnect_Fields( form ); + if (form->page) + free(form->page); + free(form); + + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_form_fields( FORM *form, FIELD **fields ) +| +| Description : Set a new association of an array of fields to a form +| +| Return Values : E_OK - no error +| E_BAD_ARGUMENT - invalid form pointer +| E_POSTED - form is posted ++--------------------------------------------------------------------------*/ +int set_form_fields(FORM * form, FIELD ** fields) +{ + FIELD **old; + int res; + + if ( !form ) + RETURN(E_BAD_ARGUMENT); + + if ( form->status & _POSTED ) + RETURN(E_POSTED); + + old = form->field; + Disconnect_Fields( form ); + + if( (res = Associate_Fields( form, fields )) != E_OK ) + Connect_Fields( form, old ); + + RETURN(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FIELD **form_fields( const FORM *form ) +| +| Description : Retrieve array of fields +| +| Return Values : Pointer to field array ++--------------------------------------------------------------------------*/ +FIELD **form_fields(const FORM * form) +{ + return (Normalize_Form( form )->field); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int field_count( const FORM *form ) +| +| Description : Retrieve number of fields +| +| Return Values : Number of fields, -1 if none are defined ++--------------------------------------------------------------------------*/ +int field_count(const FORM * form) +{ + return (Normalize_Form( form )->maxfield); +} + +/* frm_def.c ends here */ diff --git a/Source/CursesDialog/form/frm_driver.c b/Source/CursesDialog/form/frm_driver.c new file mode 100644 index 0000000..e4e72aa --- /dev/null +++ b/Source/CursesDialog/form/frm_driver.c @@ -0,0 +1,3883 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ +#include "form.priv.h" + +/* AIX seems to define this */ +#undef lines +#undef columns + +MODULE_ID("$Id$") + +/* These declarations are missing from curses.h on some platforms. */ +extern int winnstr(WINDOW *, char *, int); +#if defined(__DECCXX_VER) || (defined(__GNUC__) && defined(__osf__)) +extern int waddnstr(WINDOW *,const char *const,int); +extern void wbkgdset(WINDOW *,chtype); +#ifndef untouchwin +extern int untouchwin(WINDOW *); +#endif +extern void wcursyncup(WINDOW *); +extern int copywin(const WINDOW*,WINDOW*,int,int,int,int,int,int,int); +extern bool is_linetouched(WINDOW *,int); +extern void wsyncup(WINDOW *); +extern WINDOW *derwin(WINDOW *,int,int,int,int); +extern int winsnstr(WINDOW *, const char *,int); +extern int winsdelln(WINDOW *,int); +#endif + +/*---------------------------------------------------------------------------- + This is the core module of the form library. It contains the majority + of the driver routines as well as the form_driver function. + + Essentially this module is nearly the whole library. This is because + all the functions in this module depends on some others in the module, + so it makes no sense to split them into separate files because they + will always be linked together. The only acceptable concern is turnaround + time for this module, but now we have all Pentiums or Riscs, so what! + + The driver routines are grouped into nine generic categories: + + a) Page Navigation ( all functions prefixed by PN_ ) + The current page of the form is left and some new page is + entered. + b) Inter-Field Navigation ( all functions prefixed by FN_ ) + The current field of the form is left and some new field is + entered. + c) Intra-Field Navigation ( all functions prefixed by IFN_ ) + The current position in the current field is changed. + d) Vertical Scrolling ( all functions prefixed by VSC_ ) + Esseantially this is a specialization of Intra-Field navigation. + It has to check for a multi-line field. + e) Horizontal Scrolling ( all functions prefixed by HSC_ ) + Esseantially this is a specialization of Intra-Field navigation. + It has to check for a single-line field. + f) Field Editing ( all functions prefixed by FE_ ) + The content of the current field is changed + g) Edit Mode requests ( all functions prefixed by EM_ ) + Switching between insert and overlay mode + h) Field-Validation requests ( all functions prefixed by FV_ ) + Perform verifications of the field. + i) Choice requests ( all functions prefixed by CR_ ) + Requests to enumerate possible field values + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Some remarks on the placements of assert() macros : + I use them only on "strategic" places, i.e. top level entries where + I want to make sure that things are set correctly. Throughout subordinate + routines I omit them mostly. + --------------------------------------------------------------------------*/ + +/* +Some options that may effect compatibility in behavior to SVr4 forms, +but they are here to allow a more intuitive and user friendly behaviour of +our form implementation. This doesn't affect the API, so we feel it is +uncritical. + +The initial implementation tries to stay very close with the behaviour +of the original SVr4 implementation, although in some areas it is quite +clear that this isn't the most appropriate way. As far as possible this +sources will allow you to build a forms lib that behaves quite similar +to SVr4, but now and in the future we will give you better options. +Perhaps at some time we will make this configurable at runtime. +*/ + +/* Implement a more user-friendly previous/next word behaviour */ +#define FRIENDLY_PREV_NEXT_WORD (1) +/* Fix the wrong behaviour for forms with all fields inactive */ +#define FIX_FORM_INACTIVE_BUG (1) +/* Allow dynamic field growth also when navigating past the end */ +#define GROW_IF_NAVIGATE (1) + +/*---------------------------------------------------------------------------- + Forward references to some internally used static functions + --------------------------------------------------------------------------*/ +static int Inter_Field_Navigation ( int (* const fct) (FORM *), FORM * form ); +static int FN_Next_Field (FORM * form); +static int FN_Previous_Field (FORM * form); +static int FE_New_Line(FORM *); +static int FE_Delete_Previous(FORM *); + +/*---------------------------------------------------------------------------- + Macro Definitions. + + Some Remarks on that: I use the convention to use UPPERCASE for constants + defined by Macros. If I provide a macro as a kind of inline routine to + provide some logic, I use my Upper_Lower case style. + --------------------------------------------------------------------------*/ + +/* Calculate the position of a single row in a field buffer */ +#define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols) + +/* Calculate start address for the fields buffer# N */ +#define Address_Of_Nth_Buffer(field,N) \ + ((field)->buf + (N)*(1+Buffer_Length(field))) + +/* Calculate the start address of the row in the fields specified buffer# N */ +#define Address_Of_Row_In_Nth_Buffer(field,N,row) \ + (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row)) + +/* Calculate the start address of the row in the fields primary buffer */ +#define Address_Of_Row_In_Buffer(field,row) \ + Address_Of_Row_In_Nth_Buffer(field,0,row) + +/* Calculate the start address of the row in the forms current field + buffer# N */ +#define Address_Of_Current_Row_In_Nth_Buffer(form,N) \ + Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow) + +/* Calculate the start address of the row in the forms current field + primary buffer */ +#define Address_Of_Current_Row_In_Buffer(form) \ + Address_Of_Current_Row_In_Nth_Buffer(form,0) + +/* Calculate the address of the cursor in the forms current field + primary buffer */ +#define Address_Of_Current_Position_In_Nth_Buffer(form,N) \ + (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol) + +/* Calculate the address of the cursor in the forms current field + buffer# N */ +#define Address_Of_Current_Position_In_Buffer(form) \ + Address_Of_Current_Position_In_Nth_Buffer(form,0) + +/* Logic to decide whether or not a field is actually a field with + vertical or horizontal scrolling */ +#define Is_Scroll_Field(field) \ + (((field)->drows > (field)->rows) || \ + ((field)->dcols > (field)->cols)) + +/* Logic to decide whether or not a field needs to have an individual window + instead of a derived window because it contains invisible parts. + This is true for non-public fields and for scrollable fields. */ +#define Has_Invisible_Parts(field) \ + (!((field)->opts & O_PUBLIC) || \ + Is_Scroll_Field(field)) + +/* Logic to decide whether or not a field needs justification */ +#define Justification_Allowed(field) \ + (((field)->just != NO_JUSTIFICATION) && \ + (Single_Line_Field(field)) && \ + (((field)->dcols == (field)->cols) && \ + ((field)->opts & O_STATIC)) ) + +/* Logic to determine whether or not a dynamic field may still grow */ +#define Growable(field) ((field)->status & _MAY_GROW) + +/* Macro to set the attributes for a fields window */ +#define Set_Field_Window_Attributes(field,win) \ +( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \ + wattrset((win),(field)->fore) ) + +/* Logic to decide whether or not a field really appears on the form */ +#define Field_Really_Appears(field) \ + ((field->form) &&\ + (field->form->status & _POSTED) &&\ + (field->opts & O_VISIBLE) &&\ + (field->page == field->form->curpage)) + +/* Logic to determine whether or not we are on the first position in the + current field */ +#define First_Position_In_Current_Field(form) \ + (((form)->currow==0) && ((form)->curcol==0)) + + +#define Minimum(a,b) (((a)<=(b)) ? (a) : (b)) +#define Maximum(a,b) (((a)>=(b)) ? (a) : (b)) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static char *Get_Start_Of_Data(char * buf, int blen) +| +| Description : Return pointer to first non-blank position in buffer. +| If buffer is empty return pointer to buffer itself. +| +| Return Values : Pointer to first non-blank position in buffer ++--------------------------------------------------------------------------*/ +INLINE static char *Get_Start_Of_Data(char * buf, int blen) +{ + char *p = buf; + char *end = &buf[blen]; + + assert(buf && blen>=0); + while( (p < end) && is_blank(*p) ) + p++; + return( (p==end) ? buf : p ); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static char *After_End_Of_Data(char * buf, int blen) +| +| Description : Return pointer after last non-blank position in buffer. +| If buffer is empty, return pointer to buffer itself. +| +| Return Values : Pointer to position after last non-blank position in +| buffer. ++--------------------------------------------------------------------------*/ +INLINE static char *After_End_Of_Data(char * buf,int blen) +{ + char *p = &buf[blen]; + + assert(buf && blen>=0); + while( (p>buf) && is_blank(p[-1]) ) + p--; + return( p ); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static char *Get_First_Whitespace_Character( +| char * buf, int blen) +| +| Description : Position to the first whitespace character. +| +| Return Values : Pointer to first whitespace character in buffer. ++--------------------------------------------------------------------------*/ +INLINE static char *Get_First_Whitespace_Character(char * buf, int blen) +{ + char *p = buf; + char *end = &p[blen]; + + assert(buf && blen>=0); + while( (p < end) && !is_blank(*p)) + p++; + return( (p==end) ? buf : p ); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static char *After_Last_Whitespace_Character( +| char * buf, int blen) +| +| Description : Get the position after the last whitespace character. +| +| Return Values : Pointer to position after last whitespace character in +| buffer. ++--------------------------------------------------------------------------*/ +INLINE static char *After_Last_Whitespace_Character(char * buf, int blen) +{ + char *p = &buf[blen]; + + assert(buf && blen>=0); + while( (p>buf) && !is_blank(p[-1]) ) + p--; + return( p ); +} + +/* Set this to 1 to use the div_t version. This is a good idea if your + compiler has an intrinsic div() support. Unfortunately GNU-C has it + not yet. + N.B.: This only works if form->curcol follows immediately form->currow + and both are of type int. +*/ +#define USE_DIV_T (0) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Adjust_Cursor_Position( +| FORM * form, const char * pos) +| +| Description : Set current row and column of the form to values +| corresponding to the buffer position. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos) +{ + FIELD *field; + int idx; + + field = form->current; + assert( pos >= field->buf && field->dcols > 0); + idx = (int)( pos - field->buf ); +#if USE_DIV_T + *((div_t *)&(form->currow)) = div(idx,field->dcols); +#else + form->currow = idx / field->dcols; + form->curcol = idx - field->cols * form->currow; +#endif + if ( field->drows < form->currow ) + form->currow = 0; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Buffer_To_Window( +| const FIELD * field, +| WINDOW * win) +| +| Description : Copy the buffer to the window. If its a multiline +| field, the buffer is split to the lines of the +| window without any editing. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Buffer_To_Window(const FIELD * field, WINDOW * win) +{ + int width, height; + int len; + int row; + char *pBuffer; + + assert(win && field); + + getmaxyx(win, height, width); + + for(row=0, pBuffer=field->buf; + row < height; + row++, pBuffer += width ) + { + if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0) + { + wmove( win, row, 0 ); + waddnstr( win, pBuffer, len ); + } + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Window_To_Buffer( +| WINDOW * win, +| FIELD * field) +| +| Description : Copy the content of the window into the buffer. +| The multiple lines of a window are simply +| concatenated into the buffer. Pad characters in +| the window will be replaced by blanks in the buffer. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Window_To_Buffer(WINDOW * win, FIELD * field) +{ + int pad; + int len = 0; + char *p; + int row, height, width; + + assert(win && field && field->buf ); + + pad = field->pad; + p = field->buf; + getmaxyx(win, height, width); + + for(row=0; (row < height) && (row < field->drows); row++ ) + { + wmove( win, row, 0 ); + len += winnstr( win, p+len, field->dcols ); + } + p[len] = '\0'; + + /* replace visual padding character by blanks in buffer */ + if (pad != C_BLANK) + { + int i; + for(i=0; i<len; i++, p++) + { + if (*p==pad) + *p = C_BLANK; + } + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Synchronize_Buffer(FORM * form) +| +| Description : If there was a change, copy the content of the +| window into the buffer, so the buffer is synchronized +| with the windows content. We have to indicate that the +| buffer needs validation due to the change. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +INLINE static void Synchronize_Buffer(FORM * form) +{ + if (form->status & _WINDOW_MODIFIED) + { + form->status &= ~_WINDOW_MODIFIED; + form->status |= _FCHECK_REQUIRED; + Window_To_Buffer(form->w,form->current); + wmove(form->w,form->currow,form->curcol); + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Field_Grown( FIELD *field, int amount) +| +| Description : This function is called for growable dynamic fields +| only. It has to increase the buffers and to allocate +| a new window for this field. +| This function has the side effect to set a new +| field-buffer pointer, the dcols and drows values +| as well as a new current Window for the field. +| +| Return Values : TRUE - field successfully increased +| FALSE - there was some error ++--------------------------------------------------------------------------*/ +static bool Field_Grown(FIELD * field, int amount) +{ + bool result = FALSE; + + if (field && Growable(field)) + { + bool single_line_field = Single_Line_Field(field); + int old_buflen = Buffer_Length(field); + int new_buflen; + int old_dcols = field->dcols; + int old_drows = field->drows; + char *oldbuf = field->buf; + char *newbuf; + + int growth; + FORM *form = field->form; + bool need_visual_update = ((form != (FORM *)0) && + (form->status & _POSTED) && + (form->current==field)); + + if (need_visual_update) + Synchronize_Buffer(form); + + if (single_line_field) + { + growth = field->cols * amount; + if (field->maxgrow) + growth = Minimum(field->maxgrow - field->dcols,growth); + field->dcols += growth; + if (field->dcols == field->maxgrow) + field->status &= ~_MAY_GROW; + } + else + { + growth = (field->rows + field->nrow) * amount; + if (field->maxgrow) + growth = Minimum(field->maxgrow - field->drows,growth); + field->drows += growth; + if (field->drows == field->maxgrow) + field->status &= ~_MAY_GROW; + } + /* drows, dcols changed, so we get really the new buffer length */ + new_buflen = Buffer_Length(field); + newbuf=(char *)malloc((size_t)Total_Buffer_Size(field)); + if (!newbuf) + { /* restore to previous state */ + field->dcols = old_dcols; + field->drows = old_drows; + if (( single_line_field && (field->dcols!=field->maxgrow)) || + (!single_line_field && (field->drows!=field->maxgrow))) + field->status |= _MAY_GROW; + return FALSE; + } + else + { /* Copy all the buffers. This is the reason why we can't + just use realloc(). + */ + int i; + char *old_bp; + char *new_bp; + + field->buf = newbuf; + for(i=0;i<=field->nbuf;i++) + { + new_bp = Address_Of_Nth_Buffer(field,i); + old_bp = oldbuf + i*(1+old_buflen); + memcpy(new_bp,old_bp,(size_t)old_buflen); + if (new_buflen > old_buflen) + memset(new_bp + old_buflen,C_BLANK, + (size_t)(new_buflen - old_buflen)); + *(new_bp + new_buflen) = '\0'; + } + + if (need_visual_update) + { + WINDOW *new_window = newpad(field->drows,field->dcols); + if (!new_window) + { /* restore old state */ + field->dcols = old_dcols; + field->drows = old_drows; + field->buf = oldbuf; + if (( single_line_field && + (field->dcols!=field->maxgrow)) || + (!single_line_field && + (field->drows!=field->maxgrow))) + field->status |= _MAY_GROW; + free( newbuf ); + return FALSE; + } + assert(form!=(FORM *)0); + delwin(form->w); + form->w = new_window; + Set_Field_Window_Attributes(field,form->w); + werase(form->w); + Buffer_To_Window(field,form->w); + untouchwin(form->w); + wmove(form->w,form->currow,form->curcol); + } + + free(oldbuf); + /* reflect changes in linked fields */ + if (field != field->link) + { + FIELD *linked_field; + for(linked_field = field->link; + linked_field!= field; + linked_field = linked_field->link) + { + linked_field->buf = field->buf; + linked_field->drows = field->drows; + linked_field->dcols = field->dcols; + } + } + result = TRUE; + } + } + return(result); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int _nc_Position_Form_Cursor(FORM * form) +| +| Description : Position the cursor in the window for the current +| field to be in sync. with the currow and curcol +| values. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid form pointer +| E_SYSTEM_ERROR - form has no current field or +| field-window ++--------------------------------------------------------------------------*/ +int +_nc_Position_Form_Cursor(FORM * form) +{ + FIELD *field; + WINDOW *formwin; + + if (!form) + return(E_BAD_ARGUMENT); + + if (!form->w || !form->current) + return(E_SYSTEM_ERROR); + + field = form->current; + formwin = Get_Form_Window(form); + + wmove( form->w, form->currow, form->curcol ); + if ( Has_Invisible_Parts(field) ) + { + /* in this case fieldwin isn't derived from formwin, so we have + to move the cursor in formwin by hand... */ + wmove(formwin, + field->frow + form->currow - form->toprow, + field->fcol + form->curcol - form->begincol); + wcursyncup(formwin); + } + else + wcursyncup(form->w); + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int _nc_Refresh_Current_Field(FORM * form) +| +| Description : Propagate the changes in the fields window to the +| window of the form. +| +| Return Values : E_OK - on success +| E_BAD_ARGUMENT - invalid form pointer +| E_SYSTEM_ERROR - general error ++--------------------------------------------------------------------------*/ +int +_nc_Refresh_Current_Field(FORM * form) +{ + WINDOW *formwin; + FIELD *field; + + if (!form) + RETURN(E_BAD_ARGUMENT); + + if (!form->w || !form->current) + RETURN(E_SYSTEM_ERROR); + + field = form->current; + formwin = Get_Form_Window(form); + + if (field->opts & O_PUBLIC) + { + if (Is_Scroll_Field(field)) + { + /* Again, in this case the fieldwin isn't derived from formwin, + so we have to perform a copy operation. */ + if (Single_Line_Field(field)) + { /* horizontal scrolling */ + if (form->curcol < form->begincol) + form->begincol = form->curcol; + else + { + if (form->curcol >= (form->begincol + field->cols)) + form->begincol = form->curcol - field->cols + 1; + } + copywin(form->w, + formwin, + 0, + form->begincol, + field->frow, + field->fcol, + field->frow, + field->cols + field->fcol - 1, + 0); + } + else + { /* A multiline, i.e. vertical scrolling field */ + int row_after_bottom,first_modified_row,first_unmodified_row; + + if (field->drows > field->rows) + { + row_after_bottom = form->toprow + field->rows; + if (form->currow < form->toprow) + { + form->toprow = form->currow; + field->status |= _NEWTOP; + } + if (form->currow >= row_after_bottom) + { + form->toprow = form->currow - field->rows + 1; + field->status |= _NEWTOP; + } + if (field->status & _NEWTOP) + { /* means we have to copy whole range */ + first_modified_row = form->toprow; + first_unmodified_row = first_modified_row + field->rows; + field->status &= ~_NEWTOP; + } + else + { /* we try to optimize : finding the range of touched + lines */ + first_modified_row = form->toprow; + while(first_modified_row < row_after_bottom) + { + if (is_linetouched(form->w,first_modified_row)) + break; + first_modified_row++; + } + first_unmodified_row = first_modified_row; + while(first_unmodified_row < row_after_bottom) + { + if (!is_linetouched(form->w,first_unmodified_row)) + break; + first_unmodified_row++; + } + } + } + else + { + first_modified_row = form->toprow; + first_unmodified_row = first_modified_row + field->rows; + } + if (first_unmodified_row != first_modified_row) + copywin(form->w, + formwin, + first_modified_row, + 0, + field->frow + first_modified_row - form->toprow, + field->fcol, + field->frow + first_unmodified_row - form->toprow - 1, + field->cols + field->fcol - 1, + 0); + } + wsyncup(formwin); + } + else + { /* if the field-window is simply a derived window, i.e. contains + no invisible parts, the whole thing is trivial + */ + wsyncup(form->w); + } + } + untouchwin(form->w); + return _nc_Position_Form_Cursor(form); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Perform_Justification( +| FIELD * field, +| WINDOW * win) +| +| Description : Output field with requested justification +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Perform_Justification(FIELD * field, WINDOW * win) +{ + char *bp; + int len; + int col = 0; + + bp = Get_Start_Of_Data(field->buf,Buffer_Length(field)); + len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp); + + if (len>0) + { + assert(win && (field->drows == 1) && (field->dcols == field->cols)); + + switch(field->just) + { + case JUSTIFY_LEFT: + break; + case JUSTIFY_CENTER: + col = (field->cols - len)/2; + break; + case JUSTIFY_RIGHT: + col = field->cols - len; + break; + default: + break; + } + + wmove(win,0,col); + waddnstr(win,bp,len); + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Undo_Justification( +| FIELD * field, +| WINDOW * win) +| +| Description : Display field without any justification, i.e. +| left justified +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Undo_Justification(FIELD * field, WINDOW * win) +{ + char *bp; + int len; + + bp = Get_Start_Of_Data(field->buf,Buffer_Length(field)); + len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp); + + if (len>0) + { + assert(win != 0); + wmove(win,0,0); + waddnstr(win,bp,len); + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_Char( +| FIELDTYPE * typ, +| int ch, +| TypeArgument *argp) +| +| Description : Perform a single character check for character ch +| according to the fieldtype instance. +| +| Return Values : TRUE - Character is valid +| FALSE - Character is invalid ++--------------------------------------------------------------------------*/ +static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp) +{ + if (typ) + { + if (typ->status & _LINKED_TYPE) + { + assert(argp != 0); + return( + Check_Char(typ->left ,ch,argp->left ) || + Check_Char(typ->right,ch,argp->right) ); + } + else + { + if (typ->ccheck) + return typ->ccheck(ch,(void *)argp); + } + } + return (isprint((unsigned char)ch) ? TRUE : FALSE); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Display_Or_Erase_Field( +| FIELD * field, +| bool bEraseFlag) +| +| Description : Create a subwindow for the field and display the +| buffer contents (apply justification if required) +| or simply erase the field. +| +| Return Values : E_OK - on success +| E_SYSTEM_ERROR - some error (typical no memory) ++--------------------------------------------------------------------------*/ +static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag) +{ + WINDOW *win; + WINDOW *fwin; + + if (!field) + return E_SYSTEM_ERROR; + + fwin = Get_Form_Window(field->form); + win = derwin(fwin, + field->rows,field->cols,field->frow,field->fcol); + + if (!win) + return E_SYSTEM_ERROR; + else + { + if (field->opts & O_VISIBLE) + Set_Field_Window_Attributes(field,win); + else + { +#if defined(__LSB_VERSION__) + /* getattrs() would be handy, but it is not part of LSB 4.0 */ + attr_t fwinAttrs; + short fwinPair; + wattr_get(fwin, &fwinAttrs, &fwinPair, 0); + wattr_set(win, fwinAttrs, fwinPair, 0); +#else + wattrset(win,getattrs(fwin)); +#endif + } + werase(win); + } + + if (!bEraseFlag) + { + if (field->opts & O_PUBLIC) + { + if (Justification_Allowed(field)) + Perform_Justification(field,win); + else + Buffer_To_Window(field,win); + } + field->status &= ~_NEWTOP; + } + wsyncup(win); + delwin(win); + return E_OK; +} + +/* Macros to preset the bEraseFlag */ +#define Display_Field(field) Display_Or_Erase_Field(field,FALSE) +#define Erase_Field(field) Display_Or_Erase_Field(field,TRUE) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Synchronize_Field(FIELD * field) +| +| Description : Synchronize the windows content with the value in +| the buffer. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid field pointer +| E_SYSTEM_ERROR - some severe basic error ++--------------------------------------------------------------------------*/ +static int Synchronize_Field(FIELD * field) +{ + FORM *form; + int res = E_OK; + + if (!field) + return(E_BAD_ARGUMENT); + + if (((form=field->form) != (FORM *)0) + && Field_Really_Appears(field)) + { + if (field == form->current) + { + form->currow = form->curcol = form->toprow = form->begincol = 0; + werase(form->w); + + if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) ) + Undo_Justification( field, form->w ); + else + Buffer_To_Window( field, form->w ); + + field->status |= _NEWTOP; + res = _nc_Refresh_Current_Field( form ); + } + else + res = Display_Field( field ); + } + field->status |= _CHANGED; + return(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Synchronize_Linked_Fields(FIELD * field) +| +| Description : Propagate the Synchronize_Field function to all linked +| fields. The first error that occurs in the sequence +| of updates is the returnvalue. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid field pointer +| E_SYSTEM_ERROR - some severe basic error ++--------------------------------------------------------------------------*/ +static int Synchronize_Linked_Fields(FIELD * field) +{ + FIELD *linked_field; + int res = E_OK; + int syncres; + + if (!field) + return(E_BAD_ARGUMENT); + + if (!field->link) + return(E_SYSTEM_ERROR); + + for(linked_field = field->link; + linked_field!= field; + linked_field = linked_field->link ) + { + if (((syncres=Synchronize_Field(linked_field)) != E_OK) && + (res==E_OK)) + res = syncres; + } + return(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int _nc_Synchronize_Attributes(FIELD * field) +| +| Description : If a fields visual attributes have changed, this +| routine is called to propagate those changes to the +| screen. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid field pointer +| E_SYSTEM_ERROR - some severe basic error ++--------------------------------------------------------------------------*/ +int _nc_Synchronize_Attributes(FIELD * field) +{ + FORM *form; + int res = E_OK; + WINDOW *formwin; + + if (!field) + return(E_BAD_ARGUMENT); + + if (((form=field->form) != (FORM *)0) + && Field_Really_Appears(field)) + { + if (form->current==field) + { + Synchronize_Buffer(form); + Set_Field_Window_Attributes(field,form->w); + werase(form->w); + if (field->opts & O_PUBLIC) + { + if (Justification_Allowed(field)) + Undo_Justification(field,form->w); + else + Buffer_To_Window(field,form->w); + } + else + { + formwin = Get_Form_Window(form); + copywin(form->w,formwin, + 0,0, + field->frow,field->fcol, + field->rows-1,field->cols-1,0); + wsyncup(formwin); + Buffer_To_Window(field,form->w); + field->status |= _NEWTOP; /* fake refresh to paint all */ + _nc_Refresh_Current_Field(form); + } + } + else + { + res = Display_Field(field); + } + } + return(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int _nc_Synchronize_Options(FIELD * field, +| Field_Options newopts) +| +| Description : If a fields options have changed, this routine is +| called to propagate these changes to the screen and +| to really change the behaviour of the field. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid field pointer +| E_SYSTEM_ERROR - some severe basic error ++--------------------------------------------------------------------------*/ +int +_nc_Synchronize_Options(FIELD *field, Field_Options newopts) +{ + Field_Options oldopts; + Field_Options changed_opts; + FORM *form; + int res = E_OK; + + if (!field) + return(E_BAD_ARGUMENT); + + oldopts = field->opts; + changed_opts = oldopts ^ newopts; + field->opts = newopts; + form = field->form; + + if (form) + { + if (form->current == field) + { + field->opts = oldopts; + return(E_CURRENT); + } + + if (form->status & _POSTED) + { + if (form->curpage == field->page) + { + if (changed_opts & O_VISIBLE) + { + if (newopts & O_VISIBLE) + res = Display_Field(field); + else + res = Erase_Field(field); + } + else + { + if ((changed_opts & O_PUBLIC) && + (newopts & O_VISIBLE)) + res = Display_Field(field); + } + } + } + } + + if (changed_opts & O_STATIC) + { + bool single_line_field = Single_Line_Field(field); + int res2 = E_OK; + + if (newopts & O_STATIC) + { /* the field becomes now static */ + field->status &= ~_MAY_GROW; + /* if actually we have no hidden columns, justification may + occur again */ + if (single_line_field && + (field->cols == field->dcols) && + (field->just != NO_JUSTIFICATION) && + Field_Really_Appears(field)) + { + res2 = Display_Field(field); + } + } + else + { /* field is no longer static */ + if ((field->maxgrow==0) || + ( single_line_field && (field->dcols < field->maxgrow)) || + (!single_line_field && (field->drows < field->maxgrow))) + { + field->status |= _MAY_GROW; + /* a field with justification now changes its behaviour, + so we must redisplay it */ + if (single_line_field && + (field->just != NO_JUSTIFICATION) && + Field_Really_Appears(field)) + { + res2 = Display_Field(field); + } + } + } + if (res2 != E_OK) + res = res2; + } + + return(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int _nc_Set_Current_Field(FORM * form, +| FIELD * newfield) +| +| Description : Make the newfield the new current field. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid form or field pointer +| E_SYSTEM_ERROR - some severe basic error ++--------------------------------------------------------------------------*/ +int +_nc_Set_Current_Field(FORM *form, FIELD *newfield) +{ + FIELD *field; + WINDOW *new_window; + + if (!form || !newfield || !form->current || (newfield->form!=form)) + return(E_BAD_ARGUMENT); + + if ( (form->status & _IN_DRIVER) ) + return(E_BAD_STATE); + + if (!(form->field)) + return(E_NOT_CONNECTED); + + field = form->current; + + if ((field!=newfield) || + !(form->status & _POSTED)) + { + if ((form->w) && + (field->opts & O_VISIBLE) && + (field->form->curpage == field->page)) + { + _nc_Refresh_Current_Field(form); + if (field->opts & O_PUBLIC) + { + if (field->drows > field->rows) + { + if (form->toprow==0) + field->status &= ~_NEWTOP; + else + field->status |= _NEWTOP; + } + else + { + if (Justification_Allowed(field)) + { + Window_To_Buffer(form->w,field); + werase(form->w); + Perform_Justification(field,form->w); + wsyncup(form->w); + } + } + } + delwin(form->w); + } + + field = newfield; + + if (Has_Invisible_Parts(field)) + new_window = newpad(field->drows,field->dcols); + else + new_window = derwin(Get_Form_Window(form), + field->rows,field->cols,field->frow,field->fcol); + + if (!new_window) + return(E_SYSTEM_ERROR); + + form->current = field; + form->w = new_window; + form->status &= ~_WINDOW_MODIFIED; + Set_Field_Window_Attributes(field,form->w); + + if (Has_Invisible_Parts(field)) + { + werase(form->w); + Buffer_To_Window(field,form->w); + } + else + { + if (Justification_Allowed(field)) + { + werase(form->w); + Undo_Justification(field,form->w); + wsyncup(form->w); + } + } + + untouchwin(form->w); + } + + form->currow = form->curcol = form->toprow = form->begincol = 0; + return(E_OK); +} + +/*---------------------------------------------------------------------------- + Intra-Field Navigation routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Next_Character(FORM * form) +| +| Description : Move to the next character in the field. In a multiline +| field this wraps at the end of the line. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - at the rightmost position ++--------------------------------------------------------------------------*/ +static int IFN_Next_Character(FORM * form) +{ + FIELD *field = form->current; + + if ((++(form->curcol))==field->dcols) + { + if ((++(form->currow))==field->drows) + { +#if GROW_IF_NAVIGATE + if (!Single_Line_Field(field) && Field_Grown(field,1)) { + form->curcol = 0; + return(E_OK); + } +#endif + form->currow--; +#if GROW_IF_NAVIGATE + if (Single_Line_Field(field) && Field_Grown(field,1)) + return(E_OK); +#endif + form->curcol--; + return(E_REQUEST_DENIED); + } + form->curcol = 0; + } + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Previous_Character(FORM * form) +| +| Description : Move to the previous character in the field. In a +| multiline field this wraps and the beginning of the +| line. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - at the leftmost position ++--------------------------------------------------------------------------*/ +static int IFN_Previous_Character(FORM * form) +{ + if ((--(form->curcol))<0) + { + if ((--(form->currow))<0) + { + form->currow++; + form->curcol++; + return(E_REQUEST_DENIED); + } + form->curcol = form->current->dcols - 1; + } + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Next_Line(FORM * form) +| +| Description : Move to the beginning of the next line in the field +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - at the last line ++--------------------------------------------------------------------------*/ +static int IFN_Next_Line(FORM * form) +{ + FIELD *field = form->current; + + if ((++(form->currow))==field->drows) + { +#if GROW_IF_NAVIGATE + if (!Single_Line_Field(field) && Field_Grown(field,1)) + return(E_OK); +#endif + form->currow--; + return(E_REQUEST_DENIED); + } + form->curcol = 0; + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Previous_Line(FORM * form) +| +| Description : Move to the beginning of the previous line in the field +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - at the first line ++--------------------------------------------------------------------------*/ +static int IFN_Previous_Line(FORM * form) +{ + if ( (--(form->currow)) < 0 ) + { + form->currow++; + return(E_REQUEST_DENIED); + } + form->curcol = 0; + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Next_Word(FORM * form) +| +| Description : Move to the beginning of the next word in the field. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - there is no next word ++--------------------------------------------------------------------------*/ +static int IFN_Next_Word(FORM * form) +{ + FIELD *field = form->current; + char *bp = Address_Of_Current_Position_In_Buffer(form); + char *s; + char *t; + + /* We really need access to the data, so we have to synchronize */ + Synchronize_Buffer(form); + + /* Go to the first whitespace after the current position (including + current position). This is then the startpoint to look for the + next non-blank data */ + s = Get_First_Whitespace_Character(bp,Buffer_Length(field) - + (int)(bp - field->buf)); + + /* Find the start of the next word */ + t = Get_Start_Of_Data(s,Buffer_Length(field) - + (int)(s - field->buf)); +#if !FRIENDLY_PREV_NEXT_WORD + if (s==t) + return(E_REQUEST_DENIED); + else +#endif + { + Adjust_Cursor_Position(form,t); + return(E_OK); + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Previous_Word(FORM * form) +| +| Description : Move to the beginning of the previous word in the field. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - there is no previous word ++--------------------------------------------------------------------------*/ +static int IFN_Previous_Word(FORM * form) +{ + FIELD *field = form->current; + char *bp = Address_Of_Current_Position_In_Buffer(form); + char *s; + char *t; + bool again = FALSE; + + /* We really need access to the data, so we have to synchronize */ + Synchronize_Buffer(form); + + s = After_End_Of_Data(field->buf,(int)(bp-field->buf)); + /* s points now right after the last non-blank in the buffer before bp. + If bp was in a word, s equals bp. In this case we must find the last + whitespace in the buffer before bp and repeat the game to really find + the previous word! */ + if (s==bp) + again = TRUE; + + /* And next call now goes backward to look for the last whitespace + before that, pointing right after this, so it points to the begin + of the previous word. + */ + t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf)); +#if !FRIENDLY_PREV_NEXT_WORD + if (s==t) + return(E_REQUEST_DENIED); +#endif + if (again) + { /* and do it again, replacing bp by t */ + s = After_End_Of_Data(field->buf,(int)(t - field->buf)); + t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf)); +#if !FRIENDLY_PREV_NEXT_WORD + if (s==t) + return(E_REQUEST_DENIED); +#endif + } + Adjust_Cursor_Position(form,t); + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Beginning_Of_Field(FORM * form) +| +| Description : Place the cursor at the first non-pad character in +| the field. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int IFN_Beginning_Of_Field(FORM * form) +{ + FIELD *field = form->current; + + Synchronize_Buffer(form); + Adjust_Cursor_Position(form, + Get_Start_Of_Data(field->buf,Buffer_Length(field))); + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_End_Of_Field(FORM * form) +| +| Description : Place the cursor after the last non-pad character in +| the field. If the field occupies the last position in +| the buffer, the cursos is positioned on the last +| character. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int IFN_End_Of_Field(FORM * form) +{ + FIELD *field = form->current; + char *pos; + + Synchronize_Buffer(form); + pos = After_End_Of_Data(field->buf,Buffer_Length(field)); + if (pos==(field->buf + Buffer_Length(field))) + pos--; + Adjust_Cursor_Position(form,pos); + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Beginning_Of_Line(FORM * form) +| +| Description : Place the cursor on the first non-pad character in +| the current line of the field. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int IFN_Beginning_Of_Line(FORM * form) +{ + FIELD *field = form->current; + + Synchronize_Buffer(form); + Adjust_Cursor_Position(form, + Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form), + field->dcols)); + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_End_Of_Line(FORM * form) +| +| Description : Place the cursor after the last non-pad character in the +| current line of the field. If the field occupies the +| last column in the line, the cursor is positioned on the +| last character of the line. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int IFN_End_Of_Line(FORM * form) +{ + FIELD *field = form->current; + char *pos; + char *bp; + + Synchronize_Buffer(form); + bp = Address_Of_Current_Row_In_Buffer(form); + pos = After_End_Of_Data(bp,field->dcols); + if (pos == (bp + field->dcols)) + pos--; + Adjust_Cursor_Position(form,pos); + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Left_Character(FORM * form) +| +| Description : Move one character to the left in the current line. +| This doesn't cycle. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - already in first column ++--------------------------------------------------------------------------*/ +static int IFN_Left_Character(FORM * form) +{ + if ( (--(form->curcol)) < 0 ) + { + form->curcol++; + return(E_REQUEST_DENIED); + } + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Right_Character(FORM * form) +| +| Description : Move one character to the right in the current line. +| This doesn't cycle. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - already in last column ++--------------------------------------------------------------------------*/ +static int IFN_Right_Character(FORM * form) +{ + if ( (++(form->curcol)) == form->current->dcols ) + { +#if GROW_IF_NAVIGATE + FIELD *field = form->current; + if (Single_Line_Field(field) && Field_Grown(field,1)) + return(E_OK); +#endif + --(form->curcol); + return(E_REQUEST_DENIED); + } + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Up_Character(FORM * form) +| +| Description : Move one line up. This doesn't cycle through the lines +| of the field. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - already in last column ++--------------------------------------------------------------------------*/ +static int IFN_Up_Character(FORM * form) +{ + if ( (--(form->currow)) < 0 ) + { + form->currow++; + return(E_REQUEST_DENIED); + } + return(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int IFN_Down_Character(FORM * form) +| +| Description : Move one line down. This doesn't cycle through the +| lines of the field. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - already in last column ++--------------------------------------------------------------------------*/ +static int IFN_Down_Character(FORM * form) +{ + FIELD *field = form->current; + + if ( (++(form->currow)) == field->drows ) + { +#if GROW_IF_NAVIGATE + if (!Single_Line_Field(field) && Field_Grown(field,1)) + return(E_OK); +#endif + --(form->currow); + return(E_REQUEST_DENIED); + } + return(E_OK); +} +/*---------------------------------------------------------------------------- + END of Intra-Field Navigation routines + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Vertical scrolling helper routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int VSC_Generic(FORM *form, int lines) +| +| Description : Scroll multi-line field forward (lines>0) or +| backward (lines<0) this many lines. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - can't scroll ++--------------------------------------------------------------------------*/ +static int VSC_Generic(FORM *form, int lines) +{ + FIELD *field = form->current; + int res = E_REQUEST_DENIED; + int rows_to_go = (lines > 0 ? lines : -lines); + + if (lines > 0) + { + if ( (rows_to_go + form->toprow) > (field->drows - field->rows) ) + rows_to_go = (field->drows - field->rows - form->toprow); + + if (rows_to_go > 0) + { + form->currow += rows_to_go; + form->toprow += rows_to_go; + res = E_OK; + } + } + else + { + if (rows_to_go > form->toprow) + rows_to_go = form->toprow; + + if (rows_to_go > 0) + { + form->currow -= rows_to_go; + form->toprow -= rows_to_go; + res = E_OK; + } + } + return(res); +} +/*---------------------------------------------------------------------------- + End of Vertical scrolling helper routines + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Vertical scrolling routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Vertical_Scrolling( +| int (* const fct) (FORM *), +| FORM * form) +| +| Description : Performs the generic vertical scrolling routines. +| This has to check for a multi-line field and to set +| the _NEWTOP flag if scrolling really occurred. +| +| Return Values : Propagated error code from low-level driver calls ++--------------------------------------------------------------------------*/ +static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form) +{ + int res = E_REQUEST_DENIED; + + if (!Single_Line_Field(form->current)) + { + res = fct(form); + if (res == E_OK) + form->current->status |= _NEWTOP; + } + return(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int VSC_Scroll_Line_Forward(FORM * form) +| +| Description : Scroll multi-line field forward a line +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data ahead ++--------------------------------------------------------------------------*/ +static int VSC_Scroll_Line_Forward(FORM * form) +{ + return VSC_Generic(form,1); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int VSC_Scroll_Line_Backward(FORM * form) +| +| Description : Scroll multi-line field backward a line +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data behind ++--------------------------------------------------------------------------*/ +static int VSC_Scroll_Line_Backward(FORM * form) +{ + return VSC_Generic(form,-1); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int VSC_Scroll_Page_Forward(FORM * form) +| +| Description : Scroll a multi-line field forward a page +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data ahead ++--------------------------------------------------------------------------*/ +static int VSC_Scroll_Page_Forward(FORM * form) +{ + return VSC_Generic(form,form->current->rows); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int VSC_Scroll_Half_Page_Forward(FORM * form) +| +| Description : Scroll a multi-line field forward half a page +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data ahead ++--------------------------------------------------------------------------*/ +static int VSC_Scroll_Half_Page_Forward(FORM * form) +{ + return VSC_Generic(form,(form->current->rows + 1)/2); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int VSC_Scroll_Page_Backward(FORM * form) +| +| Description : Scroll a multi-line field backward a page +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data behind ++--------------------------------------------------------------------------*/ +static int VSC_Scroll_Page_Backward(FORM * form) +{ + return VSC_Generic(form, -(form->current->rows)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int VSC_Scroll_Half_Page_Backward(FORM * form) +| +| Description : Scroll a multi-line field backward half a page +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data behind ++--------------------------------------------------------------------------*/ +static int VSC_Scroll_Half_Page_Backward(FORM * form) +{ + return VSC_Generic(form, -((form->current->rows + 1)/2)); +} +/*---------------------------------------------------------------------------- + End of Vertical scrolling routines + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Horizontal scrolling helper routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int HSC_Generic(FORM *form, int columns) +| +| Description : Scroll single-line field forward (columns>0) or +| backward (columns<0) this many columns. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - can't scroll ++--------------------------------------------------------------------------*/ +static int HSC_Generic(FORM *form, int columns) +{ + FIELD *field = form->current; + int res = E_REQUEST_DENIED; + int cols_to_go = (columns > 0 ? columns : -columns); + + if (columns > 0) + { + if ((cols_to_go + form->begincol) > (field->dcols - field->cols)) + cols_to_go = field->dcols - field->cols - form->begincol; + + if (cols_to_go > 0) + { + form->curcol += cols_to_go; + form->begincol += cols_to_go; + res = E_OK; + } + } + else + { + if ( cols_to_go > form->begincol ) + cols_to_go = form->begincol; + + if (cols_to_go > 0) + { + form->curcol -= cols_to_go; + form->begincol -= cols_to_go; + res = E_OK; + } + } + return(res); +} +/*---------------------------------------------------------------------------- + End of Horizontal scrolling helper routines + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Horizontal scrolling routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Horizontal_Scrolling( +| int (* const fct) (FORM *), +| FORM * form) +| +| Description : Performs the generic horizontal scrolling routines. +| This has to check for a single-line field. +| +| Return Values : Propagated error code from low-level driver calls ++--------------------------------------------------------------------------*/ +static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form) +{ + if (Single_Line_Field(form->current)) + return fct(form); + else + return(E_REQUEST_DENIED); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int HSC_Scroll_Char_Forward(FORM * form) +| +| Description : Scroll single-line field forward a character +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data ahead ++--------------------------------------------------------------------------*/ +static int HSC_Scroll_Char_Forward(FORM *form) +{ + return HSC_Generic(form,1); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int HSC_Scroll_Char_Backward(FORM * form) +| +| Description : Scroll single-line field backward a character +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data behind ++--------------------------------------------------------------------------*/ +static int HSC_Scroll_Char_Backward(FORM *form) +{ + return HSC_Generic(form,-1); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int HSC_Horizontal_Line_Forward(FORM* form) +| +| Description : Scroll single-line field forward a line +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data ahead ++--------------------------------------------------------------------------*/ +static int HSC_Horizontal_Line_Forward(FORM * form) +{ + return HSC_Generic(form,form->current->cols); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form) +| +| Description : Scroll single-line field forward half a line +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data ahead ++--------------------------------------------------------------------------*/ +static int HSC_Horizontal_Half_Line_Forward(FORM * form) +{ + return HSC_Generic(form,(form->current->cols + 1)/2); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int HSC_Horizontal_Line_Backward(FORM* form) +| +| Description : Scroll single-line field backward a line +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data behind ++--------------------------------------------------------------------------*/ +static int HSC_Horizontal_Line_Backward(FORM * form) +{ + return HSC_Generic(form,-(form->current->cols)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form) +| +| Description : Scroll single-line field backward half a line +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - no data behind ++--------------------------------------------------------------------------*/ +static int HSC_Horizontal_Half_Line_Backward(FORM * form) +{ + return HSC_Generic(form,-((form->current->cols + 1)/2)); +} + +/*---------------------------------------------------------------------------- + End of Horizontal scrolling routines + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Helper routines for Field Editing + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Is_There_Room_For_A_Line(FORM * form) +| +| Description : Check whether or not there is enough room in the +| buffer to enter a whole line. +| +| Return Values : TRUE - there is enough space +| FALSE - there is not enough space ++--------------------------------------------------------------------------*/ +INLINE static bool Is_There_Room_For_A_Line(FORM * form) +{ + FIELD *field = form->current; + char *begin_of_last_line, *s; + + Synchronize_Buffer(form); + begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1)); + s = After_End_Of_Data(begin_of_last_line,field->dcols); + return ((s==begin_of_last_line) ? TRUE : FALSE); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form) +| +| Description : Checks whether or not there is room for a new character +| in the current line. +| +| Return Values : TRUE - there is room +| FALSE - there is not enough room (line full) ++--------------------------------------------------------------------------*/ +INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form) +{ + int last_char_in_line; + + wmove(form->w,form->currow,form->current->dcols-1); + last_char_in_line = (int)(winch(form->w) & A_CHARTEXT); + wmove(form->w,form->currow,form->curcol); + return (((last_char_in_line == form->current->pad) || + is_blank(last_char_in_line)) ? TRUE : FALSE); +} + +#define There_Is_No_Room_For_A_Char_In_Line(f) \ + !Is_There_Room_For_A_Char_In_Line(f) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Insert_String( +| FORM * form, +| int row, +| char *txt, +| int len ) +| +| Description : Insert the 'len' characters beginning at pointer 'txt' +| into the 'row' of the 'form'. The insertion occurs +| on the beginning of the row, all other characters are +| moved to the right. After the text a pad character will +| be inserted to separate the text from the rest. If +| necessary the insertion moves characters on the next +| line to make place for the requested insertion string. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +static int Insert_String(FORM *form, int row, char *txt, int len) +{ + FIELD *field = form->current; + char *bp = Address_Of_Row_In_Buffer(field,row); + int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp); + int freelen = field->dcols - datalen; + int requiredlen = len+1; + char *split; + int result = E_REQUEST_DENIED; + char *Space; + + Space = (char*)malloc(2*sizeof(char)); + strcpy(Space, " "); + + if (freelen >= requiredlen) + { + wmove(form->w,row,0); + winsnstr(form->w,txt,len); + wmove(form->w,row,len); + winsnstr(form->w,Space,1); + free(Space); + return E_OK; + } + else + { /* we have to move characters on the next line. If we are on the + last line this may work, if the field is growable */ + if ((row == (field->drows - 1)) && Growable(field)) + { + if (!Field_Grown(field,1)) + { + free(Space); + return(E_SYSTEM_ERROR); + } + /* !!!Side-Effect : might be changed due to growth!!! */ + bp = Address_Of_Row_In_Buffer(field,row); + } + + if (row < (field->drows - 1)) + { + split = After_Last_Whitespace_Character(bp, + (int)(Get_Start_Of_Data(bp + field->dcols - requiredlen , + requiredlen) - bp)); + /* split points now to the first character of the portion of the + line that must be moved to the next line */ + datalen = (int)(split-bp); /* + freelen has to stay on this line */ + freelen = field->dcols - (datalen + freelen); /* for the next line */ + + if ((result=Insert_String(form,row+1,split,freelen))==E_OK) + { + wmove(form->w,row,datalen); + wclrtoeol(form->w); + wmove(form->w,row,0); + winsnstr(form->w,txt,len); + wmove(form->w,row,len); + winsnstr(form->w,Space,1); + free(Space); + return E_OK; + } + } + free(Space); + return(result); + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok( +| FORM * form) +| +| Description : If a character has been entered into a field, it may +| be that wrapping has to occur. This routine checks +| whether or not wrapping is required and if so, performs +| the wrapping. +| +| Return Values : E_OK - no wrapping required or wrapping +| was successful +| E_REQUEST_DENIED - +| E_SYSTEM_ERROR - some system error ++--------------------------------------------------------------------------*/ +static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form) +{ + FIELD *field = form->current; + int result = E_REQUEST_DENIED; + bool Last_Row = ((field->drows - 1) == form->currow); + + if ( (field->opts & O_WRAP) && /* wrapping wanted */ + (!Single_Line_Field(field)) && /* must be multi-line */ + (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */ + (!Last_Row || Growable(field)) ) /* there are more lines*/ + { + char *bp; + char *split; + int chars_to_be_wrapped; + int chars_to_remain_on_line; + if (Last_Row) + { /* the above logic already ensures, that in this case the field + is growable */ + if (!Field_Grown(field,1)) + return E_SYSTEM_ERROR; + } + bp = Address_Of_Current_Row_In_Buffer(form); + Window_To_Buffer(form->w,field); + split = After_Last_Whitespace_Character(bp,field->dcols); + /* split points to the first character of the sequence to be brought + on the next line */ + chars_to_remain_on_line = (int)(split - bp); + chars_to_be_wrapped = field->dcols - chars_to_remain_on_line; + if (chars_to_remain_on_line > 0) + { + if ((result=Insert_String(form,form->currow+1,split, + chars_to_be_wrapped)) == E_OK) + { + wmove(form->w,form->currow,chars_to_remain_on_line); + wclrtoeol(form->w); + if (form->curcol >= chars_to_remain_on_line) + { + form->currow++; + form->curcol -= chars_to_remain_on_line; + } + return E_OK; + } + } + else + return E_OK; + if (result!=E_OK) + { + wmove(form->w,form->currow,form->curcol); + wdelch(form->w); + Window_To_Buffer(form->w,field); + result = E_REQUEST_DENIED; + } + } + else + result = E_OK; /* wrapping was not necessary */ + return(result); +} + +/*---------------------------------------------------------------------------- + Field Editing routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Field_Editing( +| int (* const fct) (FORM *), +| FORM * form) +| +| Description : Generic routine for field editing requests. The driver +| routines are only called for editable fields, the +| _WINDOW_MODIFIED flag is set if editing occurred. +| This is somewhat special due to the overload semantics +| of the NEW_LINE and DEL_PREV requests. +| +| Return Values : Error code from low level drivers. ++--------------------------------------------------------------------------*/ +static int Field_Editing(int (* const fct) (FORM *), FORM * form) +{ + int res = E_REQUEST_DENIED; + + /* We have to deal here with the specific case of the overloaded + behaviour of New_Line and Delete_Previous requests. + They may end up in navigational requests if we are on the first + character in a field. But navigation is also allowed on non- + editable fields. + */ + if ((fct==FE_Delete_Previous) && + (form->opts & O_BS_OVERLOAD) && + First_Position_In_Current_Field(form) ) + { + res = Inter_Field_Navigation(FN_Previous_Field,form); + } + else + { + if (fct==FE_New_Line) + { + if ((form->opts & O_NL_OVERLOAD) && + First_Position_In_Current_Field(form)) + { + res = Inter_Field_Navigation(FN_Next_Field,form); + } + else + /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */ + res = fct(form); + } + else + { + /* From now on, everything must be editable */ + if (form->current->opts & O_EDIT) + { + res = fct(form); + if (res==E_OK) + form->status |= _WINDOW_MODIFIED; + } + } + } + return res; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_New_Line(FORM * form) +| +| Description : Perform a new line request. This is rather complex +| compared to other routines in this code due to the +| rather difficult to understand description in the +| manuals. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - new line not allowed +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +static int FE_New_Line(FORM * form) +{ + FIELD *field = form->current; + char *bp, *t; + bool Last_Row = ((field->drows - 1)==form->currow); + + if (form->status & _OVLMODE) + { + if (Last_Row && + (!(Growable(field) && !Single_Line_Field(field)))) + { + if (!(form->opts & O_NL_OVERLOAD)) + return(E_REQUEST_DENIED); + wclrtoeol(form->w); + /* we have to set this here, although it is also + handled in the generic routine. The reason is, + that FN_Next_Field may fail, but the form is + definitively changed */ + form->status |= _WINDOW_MODIFIED; + return Inter_Field_Navigation(FN_Next_Field,form); + } + else + { + if (Last_Row && !Field_Grown(field,1)) + { /* N.B.: due to the logic in the 'if', LastRow==TRUE + means here that the field is growable and not + a single-line field */ + return(E_SYSTEM_ERROR); + } + wclrtoeol(form->w); + form->currow++; + form->curcol = 0; + form->status |= _WINDOW_MODIFIED; + return(E_OK); + } + } + else + { /* Insert Mode */ + if (Last_Row && + !(Growable(field) && !Single_Line_Field(field))) + { + if (!(form->opts & O_NL_OVERLOAD)) + return(E_REQUEST_DENIED); + return Inter_Field_Navigation(FN_Next_Field,form); + } + else + { + bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form); + + if (!(May_Do_It || Growable(field))) + return(E_REQUEST_DENIED); + if (!May_Do_It && !Field_Grown(field,1)) + return(E_SYSTEM_ERROR); + + bp= Address_Of_Current_Position_In_Buffer(form); + t = After_End_Of_Data(bp,field->dcols - form->curcol); + wclrtoeol(form->w); + form->currow++; + form->curcol=0; + wmove(form->w,form->currow,form->curcol); + winsertln(form->w); + waddnstr(form->w,bp,(int)(t-bp)); + form->status |= _WINDOW_MODIFIED; + return E_OK; + } + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_Insert_Character(FORM * form) +| +| Description : Insert blank character at the cursor position +| +| Return Values : E_OK +| E_REQUEST_DENIED ++--------------------------------------------------------------------------*/ +static int FE_Insert_Character(FORM * form) +{ + FIELD *field = form->current; + int result = E_REQUEST_DENIED; + + if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg))) + { + bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form); + + if (There_Is_Room || + ((Single_Line_Field(field) && Growable(field)))) + { + if (!There_Is_Room && !Field_Grown(field,1)) + result = E_SYSTEM_ERROR; + else + { + winsch(form->w,(chtype)C_BLANK); + result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form); + } + } + } + return result; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_Insert_Line(FORM * form) +| +| Description : Insert a blank line at the cursor position +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - line can not be inserted ++--------------------------------------------------------------------------*/ +static int FE_Insert_Line(FORM * form) +{ + FIELD *field = form->current; + int result = E_REQUEST_DENIED; + + if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg))) + { + bool Maybe_Done = (form->currow!=(field->drows-1)) && + Is_There_Room_For_A_Line(form); + + if (!Single_Line_Field(field) && + (Maybe_Done || Growable(field))) + { + if (!Maybe_Done && !Field_Grown(field,1)) + result = E_SYSTEM_ERROR; + else + { + form->curcol = 0; + winsertln(form->w); + result = E_OK; + } + } + } + return result; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_Delete_Character(FORM * form) +| +| Description : Delete character at the cursor position +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int FE_Delete_Character(FORM * form) +{ + wdelch(form->w); + return E_OK; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_Delete_Previous(FORM * form) +| +| Description : Delete character before cursor. Again this is a rather +| difficult piece compared to others due to the overloading +| semantics of backspace. +| N.B.: The case of overloaded BS on first field position +| is already handled in the generic routine. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - Character can't be deleted ++--------------------------------------------------------------------------*/ +static int FE_Delete_Previous(FORM * form) +{ + FIELD *field = form->current; + + if (First_Position_In_Current_Field(form)) + return E_REQUEST_DENIED; + + if ( (--(form->curcol))<0 ) + { + char *this_line, *prev_line, *prev_end, *this_end; + + form->curcol++; + if (form->status & _OVLMODE) + return E_REQUEST_DENIED; + + prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1)); + this_line = Address_Of_Row_In_Buffer(field,(form->currow)); + Synchronize_Buffer(form); + prev_end = After_End_Of_Data(prev_line,field->dcols); + this_end = After_End_Of_Data(this_line,field->dcols); + if ((int)(this_end-this_line) > + (field->cols-(int)(prev_end-prev_line))) + return E_REQUEST_DENIED; + wdeleteln(form->w); + Adjust_Cursor_Position(form,prev_end); + wmove(form->w,form->currow,form->curcol); + waddnstr(form->w,this_line,(int)(this_end-this_line)); + } + else + { + wmove(form->w,form->currow,form->curcol); + wdelch(form->w); + } + return E_OK; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_Delete_Line(FORM * form) +| +| Description : Delete line at cursor position. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int FE_Delete_Line(FORM * form) +{ + form->curcol = 0; + wdeleteln(form->w); + return E_OK; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_Delete_Word(FORM * form) +| +| Description : Delete word at cursor position +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - failure ++--------------------------------------------------------------------------*/ +static int FE_Delete_Word(FORM * form) +{ + FIELD *field = form->current; + char *bp = Address_Of_Current_Row_In_Buffer(form); + char *ep = bp + field->dcols; + char *cp = bp + form->curcol; + char *s; + + Synchronize_Buffer(form); + if (is_blank(*cp)) + return E_REQUEST_DENIED; /* not in word */ + + /* move cursor to begin of word and erase to end of screen-line */ + Adjust_Cursor_Position(form, + After_Last_Whitespace_Character(bp,form->curcol)); + wmove(form->w,form->currow,form->curcol); + wclrtoeol(form->w); + + /* skip over word in buffer */ + s = Get_First_Whitespace_Character(cp,(int)(ep-cp)); + /* to begin of next word */ + s = Get_Start_Of_Data(s,(int)(ep - s)); + if ( (s!=cp) && !is_blank(*s)) + { + /* copy remaining line to window */ + waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s)))); + } + return E_OK; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_Clear_To_End_Of_Line(FORM * form) +| +| Description : Clear to end of current line. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int FE_Clear_To_End_Of_Line(FORM * form) +{ + wclrtoeol(form->w); + return E_OK; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_Clear_To_End_Of_Form(FORM * form) +| +| Description : Clear to end of form. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int FE_Clear_To_End_Of_Form(FORM * form) +{ + wclrtobot(form->w); + return E_OK; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FE_Clear_Field(FORM * form) +| +| Description : Clear entire field. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int FE_Clear_Field(FORM * form) +{ + form->currow = form->curcol = 0; + werase(form->w); + return E_OK; +} +/*---------------------------------------------------------------------------- + END of Field Editing routines + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Edit Mode routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int EM_Overlay_Mode(FORM * form) +| +| Description : Switch to overlay mode. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int EM_Overlay_Mode(FORM * form) +{ + form->status |= _OVLMODE; + return E_OK; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int EM_Insert_Mode(FORM * form) +| +| Description : Switch to insert mode +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +static int EM_Insert_Mode(FORM * form) +{ + form->status &= ~_OVLMODE; + return E_OK; +} + +/*---------------------------------------------------------------------------- + END of Edit Mode routines + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Helper routines for Choice Requests + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Next_Choice( +| FIELDTYPE * typ, +| FIELD * field, +| TypeArgument *argp) +| +| Description : Get the next field choice. For linked types this is +| done recursively. +| +| Return Values : TRUE - next choice successfully retrieved +| FALSE - couldn't retrieve next choice ++--------------------------------------------------------------------------*/ +static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp) +{ + if (!typ || !(typ->status & _HAS_CHOICE)) + return FALSE; + + if (typ->status & _LINKED_TYPE) + { + assert(argp != 0); + return( + Next_Choice(typ->left ,field,argp->left) || + Next_Choice(typ->right,field,argp->right) ); + } + else + { + assert(typ->next != 0); + return typ->next(field,(void *)argp); + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Previous_Choice( +| FIELDTYPE * typ, +| FIELD * field, +| TypeArgument *argp) +| +| Description : Get the previous field choice. For linked types this +| is done recursively. +| +| Return Values : TRUE - previous choice successfully retrieved +| FALSE - couldn't retrieve previous choice ++--------------------------------------------------------------------------*/ +static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp) +{ + if (!typ || !(typ->status & _HAS_CHOICE)) + return FALSE; + + if (typ->status & _LINKED_TYPE) + { + assert(argp != 0); + return( + Previous_Choice(typ->left ,field,argp->left) || + Previous_Choice(typ->right,field,argp->right)); + } + else + { + assert(typ->prev != 0); + return typ->prev(field,(void *)argp); + } +} +/*---------------------------------------------------------------------------- + End of Helper routines for Choice Requests + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Routines for Choice Requests + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int CR_Next_Choice(FORM * form) +| +| Description : Get the next field choice. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - next choice couldn't be retrieved ++--------------------------------------------------------------------------*/ +static int CR_Next_Choice(FORM * form) +{ + FIELD *field = form->current; + Synchronize_Buffer(form); + return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ? + E_OK : E_REQUEST_DENIED); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int CR_Previous_Choice(FORM * form) +| +| Description : Get the previous field choice. +| +| Return Values : E_OK - success +| E_REQUEST_DENIED - prev. choice couldn't be retrieved ++--------------------------------------------------------------------------*/ +static int CR_Previous_Choice(FORM * form) +{ + FIELD *field = form->current; + Synchronize_Buffer(form); + return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ? + E_OK : E_REQUEST_DENIED); +} +/*---------------------------------------------------------------------------- + End of Routines for Choice Requests + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Helper routines for Field Validations. + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_Field( +| FIELDTYPE * typ, +| FIELD * field, +| TypeArgument * argp) +| +| Description : Check the field according to its fieldtype and its +| actual arguments. For linked fieldtypes this is done +| recursively. +| +| Return Values : TRUE - field is valid +| FALSE - field is invalid. ++--------------------------------------------------------------------------*/ +static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp) +{ + if (typ) + { + if (field->opts & O_NULLOK) + { + char *bp = field->buf; + assert(bp != 0); + while(is_blank(*bp)) + { bp++; } + if (*bp == '\0') + return TRUE; + } + + if (typ->status & _LINKED_TYPE) + { + assert(argp != 0); + return( + Check_Field(typ->left ,field,argp->left ) || + Check_Field(typ->right,field,argp->right) ); + } + else + { + if (typ->fcheck) + return typ->fcheck(field,(void *)argp); + } + } + return TRUE; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : bool _nc_Internal_Validation(FORM * form ) +| +| Description : Validate the current field of the form. +| +| Return Values : TRUE - field is valid +| FALSE - field is invalid ++--------------------------------------------------------------------------*/ +bool +_nc_Internal_Validation(FORM *form) +{ + FIELD *field; + + field = form->current; + + Synchronize_Buffer(form); + if ((form->status & _FCHECK_REQUIRED) || + (!(field->opts & O_PASSOK))) + { + if (!Check_Field(field->type,field,(TypeArgument *)(field->arg))) + return FALSE; + form->status &= ~_FCHECK_REQUIRED; + field->status |= _CHANGED; + Synchronize_Linked_Fields(field); + } + return TRUE; +} +/*---------------------------------------------------------------------------- + End of Helper routines for Field Validations. + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Routines for Field Validation. + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FV_Validation(FORM * form) +| +| Description : Validate the current field of the form. +| +| Return Values : E_OK - field valid +| E_INVALID_FIELD - field not valid ++--------------------------------------------------------------------------*/ +static int FV_Validation(FORM * form) +{ + if (_nc_Internal_Validation(form)) + return E_OK; + else + return E_INVALID_FIELD; +} +/*---------------------------------------------------------------------------- + End of routines for Field Validation. + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Helper routines for Inter-Field Navigation + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static FIELD *Next_Field_On_Page(FIELD * field) +| +| Description : Get the next field after the given field on the current +| page. The order of fields is the one defined by the +| fields array. Only visible and active fields are +| counted. +| +| Return Values : Pointer to the next field. ++--------------------------------------------------------------------------*/ +INLINE static FIELD *Next_Field_On_Page(FIELD * field) +{ + FORM *form = field->form; + FIELD **field_on_page = &form->field[field->index]; + FIELD **first_on_page = &form->field[form->page[form->curpage].pmin]; + FIELD **last_on_page = &form->field[form->page[form->curpage].pmax]; + + do + { + field_on_page = + (field_on_page==last_on_page) ? first_on_page : field_on_page + 1; + if (Field_Is_Selectable(*field_on_page)) + break; + } while(field!=(*field_on_page)); + return(*field_on_page); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : FIELD* _nc_First_Active_Field(FORM * form) +| +| Description : Get the first active field on the current page, +| if there are such. If there are none, get the first +| visible field on the page. If there are also none, +| we return the first field on page and hope the best. +| +| Return Values : Pointer to calculated field. ++--------------------------------------------------------------------------*/ +FIELD* +_nc_First_Active_Field(FORM * form) +{ + FIELD **last_on_page = &form->field[form->page[form->curpage].pmax]; + FIELD *proposed = Next_Field_On_Page(*last_on_page); + + if (proposed == *last_on_page) + { /* there might be the special situation, where there is no + active and visible field on the current page. We then select + the first visible field on this readonly page + */ + if (Field_Is_Not_Selectable(proposed)) + { + FIELD **field = &form->field[proposed->index]; + FIELD **first = &form->field[form->page[form->curpage].pmin]; + + do + { + field = (field==last_on_page) ? first : field + 1; + if (((*field)->opts & O_VISIBLE)) + break; + } while(proposed!=(*field)); + + proposed = *field; + + if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE)) + { /* This means, there is also no visible field on the page. + So we propose the first one and hope the very best... + Some very clever user has designed a readonly and invisible + page on this form. + */ + proposed = *first; + } + } + } + return(proposed); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static FIELD *Previous_Field_On_Page(FIELD * field) +| +| Description : Get the previous field before the given field on the +| current page. The order of fields is the one defined by +| the fields array. Only visible and active fields are +| counted. +| +| Return Values : Pointer to the previous field. ++--------------------------------------------------------------------------*/ +INLINE static FIELD *Previous_Field_On_Page(FIELD * field) +{ + FORM *form = field->form; + FIELD **field_on_page = &form->field[field->index]; + FIELD **first_on_page = &form->field[form->page[form->curpage].pmin]; + FIELD **last_on_page = &form->field[form->page[form->curpage].pmax]; + + do + { + field_on_page = + (field_on_page==first_on_page) ? last_on_page : field_on_page - 1; + if (Field_Is_Selectable(*field_on_page)) + break; + } while(field!=(*field_on_page)); + + return (*field_on_page); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static FIELD *Sorted_Next_Field(FIELD * field) +| +| Description : Get the next field after the given field on the current +| page. The order of fields is the one defined by the +| (row,column) geometry, rows are major. +| +| Return Values : Pointer to the next field. ++--------------------------------------------------------------------------*/ +INLINE static FIELD *Sorted_Next_Field(FIELD * field) +{ + FIELD *field_on_page = field; + + do + { + field_on_page = field_on_page->snext; + if (Field_Is_Selectable(field_on_page)) + break; + } while(field_on_page!=field); + + return (field_on_page); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static FIELD *Sorted_Previous_Field(FIELD * field) +| +| Description : Get the previous field before the given field on the +| current page. The order of fields is the one defined +| by the (row,column) geometry, rows are major. +| +| Return Values : Pointer to the previous field. ++--------------------------------------------------------------------------*/ +INLINE static FIELD *Sorted_Previous_Field(FIELD * field) +{ + FIELD *field_on_page = field; + + do + { + field_on_page = field_on_page->sprev; + if (Field_Is_Selectable(field_on_page)) + break; + } while(field_on_page!=field); + + return (field_on_page); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static FIELD *Left_Neighbour_Field(FIELD * field) +| +| Description : Get the left neighbour of the field on the same line +| and the same page. Cycles through the line. +| +| Return Values : Pointer to left neighbour field. ++--------------------------------------------------------------------------*/ +INLINE static FIELD *Left_Neighbour_Field(FIELD * field) +{ + FIELD *field_on_page = field; + + /* For a field that has really a left neighbour, the while clause + immediately fails and the loop is left, positioned at the right + neighbour. Otherwise we cycle backwards through the sorted fieldlist + until we enter the same line (from the right end). + */ + do + { + field_on_page = Sorted_Previous_Field(field_on_page); + } while(field_on_page->frow != field->frow); + + return (field_on_page); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static FIELD *Right_Neighbour_Field(FIELD * field) +| +| Description : Get the right neighbour of the field on the same line +| and the same page. +| +| Return Values : Pointer to right neighbour field. ++--------------------------------------------------------------------------*/ +INLINE static FIELD *Right_Neighbour_Field(FIELD * field) +{ + FIELD *field_on_page = field; + + /* See the comments on Left_Neighbour_Field to understand how it works */ + do + { + field_on_page = Sorted_Next_Field(field_on_page); + } while(field_on_page->frow != field->frow); + + return (field_on_page); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static FIELD *Upper_Neighbour_Field(FIELD * field) +| +| Description : Because of the row-major nature of sorting the fields, +| its more difficult to define whats the upper neighbour +| field really means. We define that it must be on a +| 'previous' line (cyclic order!) and is the rightmost +| field laying on the left side of the given field. If +| this set is empty, we take the first field on the line. +| +| Return Values : Pointer to the upper neighbour field. ++--------------------------------------------------------------------------*/ +static FIELD *Upper_Neighbour_Field(FIELD * field) +{ + FIELD *field_on_page = field; + int frow = field->frow; + int fcol = field->fcol; + + /* Walk back to the 'previous' line. The second term in the while clause + just guarantees that we stop if we cycled through the line because + there might be no 'previous' line if the page has just one line. + */ + do + { + field_on_page = Sorted_Previous_Field(field_on_page); + } while(field_on_page->frow==frow && field_on_page->fcol!=fcol); + + if (field_on_page->frow!=frow) + { /* We really found a 'previous' line. We are positioned at the + rightmost field on this line */ + frow = field_on_page->frow; + + /* We walk to the left as long as we are really right of the + field. */ + while(field_on_page->frow==frow && field_on_page->fcol>fcol) + field_on_page = Sorted_Previous_Field(field_on_page); + + /* If we wrapped, just go to the right which is the first field on + the row */ + if (field_on_page->frow!=frow) + field_on_page = Sorted_Next_Field(field_on_page); + } + + return (field_on_page); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static FIELD *Down_Neighbour_Field(FIELD * field) +| +| Description : Because of the row-major nature of sorting the fields, +| its more difficult to define whats the down neighbour +| field really means. We define that it must be on a +| 'next' line (cyclic order!) and is the leftmost +| field laying on the right side of the given field. If +| this set is empty, we take the last field on the line. +| +| Return Values : Pointer to the upper neighbour field. ++--------------------------------------------------------------------------*/ +static FIELD *Down_Neighbour_Field(FIELD * field) +{ + FIELD *field_on_page = field; + int frow = field->frow; + int fcol = field->fcol; + + /* Walk forward to the 'next' line. The second term in the while clause + just guarantees that we stop if we cycled through the line because + there might be no 'next' line if the page has just one line. + */ + do + { + field_on_page = Sorted_Next_Field(field_on_page); + } while(field_on_page->frow==frow && field_on_page->fcol!=fcol); + + if (field_on_page->frow!=frow) + { /* We really found a 'next' line. We are positioned at the rightmost + field on this line */ + frow = field_on_page->frow; + + /* We walk to the right as long as we are really left of the + field. */ + while(field_on_page->frow==frow && field_on_page->fcol<fcol) + field_on_page = Sorted_Next_Field(field_on_page); + + /* If we wrapped, just go to the left which is the last field on + the row */ + if (field_on_page->frow!=frow) + field_on_page = Sorted_Previous_Field(field_on_page); + } + + return(field_on_page); +} + +/*---------------------------------------------------------------------------- + Inter-Field Navigation routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Inter_Field_Navigation( +| int (* const fct) (FORM *), +| FORM * form) +| +| Description : Generic behaviour for changing the current field, the +| field is left and a new field is entered. So the field +| must be validated and the field init/term hooks must +| be called. +| +| Return Values : E_OK - success +| E_INVALID_FIELD - field is invalid +| some other - error from subordinate call ++--------------------------------------------------------------------------*/ +static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form) +{ + int res; + + if (!_nc_Internal_Validation(form)) + res = E_INVALID_FIELD; + else + { + Call_Hook(form,fieldterm); + res = fct(form); + Call_Hook(form,fieldinit); + } + return res; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Next_Field(FORM * form) +| +| Description : Move to the next field on the current page of the form +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Next_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Next_Field_On_Page(form->current)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Previous_Field(FORM * form) +| +| Description : Move to the previous field on the current page of the +| form +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Previous_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Previous_Field_On_Page(form->current)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_First_Field(FORM * form) +| +| Description : Move to the first field on the current page of the form +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_First_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Next_Field_On_Page(form->field[form->page[form->curpage].pmax])); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Last_Field(FORM * form) +| +| Description : Move to the last field on the current page of the form +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Last_Field(FORM * form) +{ + return + _nc_Set_Current_Field(form, + Previous_Field_On_Page(form->field[form->page[form->curpage].pmin])); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Sorted_Next_Field(FORM * form) +| +| Description : Move to the sorted next field on the current page +| of the form. +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Sorted_Next_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Sorted_Next_Field(form->current)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Sorted_Previous_Field(FORM * form) +| +| Description : Move to the sorted previous field on the current page +| of the form. +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Sorted_Previous_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Sorted_Previous_Field(form->current)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Sorted_First_Field(FORM * form) +| +| Description : Move to the sorted first field on the current page +| of the form. +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Sorted_First_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Sorted_Next_Field(form->field[form->page[form->curpage].smax])); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Sorted_Last_Field(FORM * form) +| +| Description : Move to the sorted last field on the current page +| of the form. +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Sorted_Last_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Sorted_Previous_Field(form->field[form->page[form->curpage].smin])); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Left_Field(FORM * form) +| +| Description : Get the field on the left of the current field on the +| same line and the same page. Cycles through the line. +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Left_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Left_Neighbour_Field(form->current)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Right_Field(FORM * form) +| +| Description : Get the field on the right of the current field on the +| same line and the same page. Cycles through the line. +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Right_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Right_Neighbour_Field(form->current)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Up_Field(FORM * form) +| +| Description : Get the upper neighbour of the current field. This +| cycles through the page. See the comments of the +| Upper_Neighbour_Field function to understand how +| 'upper' is defined. +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Up_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Upper_Neighbour_Field(form->current)); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int FN_Down_Field(FORM * form) +| +| Description : Get the down neighbour of the current field. This +| cycles through the page. See the comments of the +| Down_Neighbour_Field function to understand how +| 'down' is defined. +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int FN_Down_Field(FORM * form) +{ + return _nc_Set_Current_Field(form, + Down_Neighbour_Field(form->current)); +} +/*---------------------------------------------------------------------------- + END of Field Navigation routines + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Helper routines for Page Navigation + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int _nc_Set_Form_Page(FORM * form, +| int page, +| FIELD * field) +| +| Description : Make the given page nr. the current page and make +| the given field the current field on the page. If +| for the field NULL is given, make the first field on +| the page the current field. The routine acts only +| if the requested page is not the current page. +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +int +_nc_Set_Form_Page(FORM * form, int page, FIELD * field) +{ + int res = E_OK; + + if ((form->curpage!=page)) + { + FIELD *last_field, *field_on_page; + + werase(Get_Form_Window(form)); + form->curpage = page; + last_field = field_on_page = form->field[form->page[page].smin]; + do + { + if (field_on_page->opts & O_VISIBLE) + if ((res=Display_Field(field_on_page))!=E_OK) + return(res); + field_on_page = field_on_page->snext; + } while(field_on_page != last_field); + + if (field) + res = _nc_Set_Current_Field(form,field); + else + /* N.B.: we don't encapsulate this by Inter_Field_Navigation(), + because this is already executed in a page navigation + context that contains field navigation + */ + res = FN_First_Field(form); + } + return(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Next_Page_Number(const FORM * form) +| +| Description : Calculate the page number following the current page +| number. This cycles if the highest page number is +| reached. +| +| Return Values : The next page number ++--------------------------------------------------------------------------*/ +INLINE static int Next_Page_Number(const FORM * form) +{ + return (form->curpage + 1) % form->maxpage; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Previous_Page_Number(const FORM * form) +| +| Description : Calculate the page number before the current page +| number. This cycles if the first page number is +| reached. +| +| Return Values : The previous page number ++--------------------------------------------------------------------------*/ +INLINE static int Previous_Page_Number(const FORM * form) +{ + return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1); +} + +/*---------------------------------------------------------------------------- + Page Navigation routines + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Page_Navigation( +| int (* const fct) (FORM *), +| FORM * form) +| +| Description : Generic behaviour for changing a page. This means +| that the field is left and a new field is entered. +| So the field must be validated and the field init/term +| hooks must be called. Because also the page is changed, +| the forms init/term hooks must be called also. +| +| Return Values : E_OK - success +| E_INVALID_FIELD - field is invalid +| some other - error from subordinate call ++--------------------------------------------------------------------------*/ +static int Page_Navigation(int (* const fct) (FORM *), FORM * form) +{ + int res; + + if (!_nc_Internal_Validation(form)) + res = E_INVALID_FIELD; + else + { + Call_Hook(form,fieldterm); + Call_Hook(form,formterm); + res = fct(form); + Call_Hook(form,forminit); + Call_Hook(form,fieldinit); + } + return res; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int PN_Next_Page(FORM * form) +| +| Description : Move to the next page of the form +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int PN_Next_Page(FORM * form) +{ + return _nc_Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int PN_Previous_Page(FORM * form) +| +| Description : Move to the previous page of the form +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int PN_Previous_Page(FORM * form) +{ + return _nc_Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int PN_First_Page(FORM * form) +| +| Description : Move to the first page of the form +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int PN_First_Page(FORM * form) +{ + return _nc_Set_Form_Page(form,0,(FIELD *)0); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int PN_Last_Page(FORM * form) +| +| Description : Move to the last page of the form +| +| Return Values : E_OK - success +| != E_OK - error from subordinate call ++--------------------------------------------------------------------------*/ +static int PN_Last_Page(FORM * form) +{ + return _nc_Set_Form_Page(form,form->maxpage-1,(FIELD *)0); +} +/*---------------------------------------------------------------------------- + END of Field Navigation routines + --------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Helper routines for the core form driver. + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Data_Entry(FORM * form,int c) +| +| Description : Enter character c into at the current position of the +| current field of the form. +| +| Return Values : E_OK - +| E_REQUEST_DENIED - +| E_SYSTEM_ERROR - ++--------------------------------------------------------------------------*/ +static int Data_Entry(FORM * form, int c) +{ + FIELD *field = form->current; + int result = E_REQUEST_DENIED; + + if ( (field->opts & O_EDIT) +#if FIX_FORM_INACTIVE_BUG + && (field->opts & O_ACTIVE) +#endif + ) + { + if ( (field->opts & O_BLANK) && + First_Position_In_Current_Field(form) && + !(form->status & _FCHECK_REQUIRED) && + !(form->status & _WINDOW_MODIFIED) ) + werase(form->w); + + if (form->status & _OVLMODE) + { + waddch(form->w,(chtype)c); + } + else /* no _OVLMODE */ + { + bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form); + + if (!(There_Is_Room || + ((Single_Line_Field(field) && Growable(field))))) + return E_REQUEST_DENIED; + + if (!There_Is_Room && !Field_Grown(field,1)) + return E_SYSTEM_ERROR; + + winsch(form->w,(chtype)c); + } + + if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK) + { + bool End_Of_Field= (((field->drows-1)==form->currow) && + ((field->dcols-1)==form->curcol)); + form->status |= _WINDOW_MODIFIED; + if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP)) + result = Inter_Field_Navigation(FN_Next_Field,form); + else + { + if (End_Of_Field && Growable(field) && !Field_Grown(field,1)) + result = E_SYSTEM_ERROR; + else + { + IFN_Next_Character(form); + result = E_OK; + } + } + } + } + return result; +} + +/* Structure to describe the binding of a request code to a function. + The member keycode codes the request value as well as the generic + routine to use for the request. The code for the generic routine + is coded in the upper 16 Bits while the request code is coded in + the lower 16 bits. + + In terms of C++ you might think of a request as a class with a + virtual method "perform". The different types of request are + derived from this base class and overload (or not) the base class + implementation of perform. +*/ +typedef struct { + int keycode; /* must be at least 32 bit: hi:mode, lo: key */ + int (*cmd)(FORM *); /* low level driver routine for this key */ +} Binding_Info; + +/* You may see this is the class-id of the request type class */ +#define ID_PN (0x00000000) /* Page navigation */ +#define ID_FN (0x00010000) /* Inter-Field navigation */ +#define ID_IFN (0x00020000) /* Intra-Field navigation */ +#define ID_VSC (0x00030000) /* Vertical Scrolling */ +#define ID_HSC (0x00040000) /* Horizontal Scrolling */ +#define ID_FE (0x00050000) /* Field Editing */ +#define ID_EM (0x00060000) /* Edit Mode */ +#define ID_FV (0x00070000) /* Field Validation */ +#define ID_CH (0x00080000) /* Choice */ +#define ID_Mask (0xffff0000) +#define Key_Mask (0x0000ffff) +#define ID_Shft (16) + +/* This array holds all the Binding Infos */ +static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] = +{ + { REQ_NEXT_PAGE |ID_PN ,PN_Next_Page}, + { REQ_PREV_PAGE |ID_PN ,PN_Previous_Page}, + { REQ_FIRST_PAGE |ID_PN ,PN_First_Page}, + { REQ_LAST_PAGE |ID_PN ,PN_Last_Page}, + + { REQ_NEXT_FIELD |ID_FN ,FN_Next_Field}, + { REQ_PREV_FIELD |ID_FN ,FN_Previous_Field}, + { REQ_FIRST_FIELD |ID_FN ,FN_First_Field}, + { REQ_LAST_FIELD |ID_FN ,FN_Last_Field}, + { REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field}, + { REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field}, + { REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field}, + { REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field}, + { REQ_LEFT_FIELD |ID_FN ,FN_Left_Field}, + { REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field}, + { REQ_UP_FIELD |ID_FN ,FN_Up_Field}, + { REQ_DOWN_FIELD |ID_FN ,FN_Down_Field}, + + { REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character}, + { REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character}, + { REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line}, + { REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line}, + { REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word}, + { REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word}, + { REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field}, + { REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field}, + { REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line}, + { REQ_END_LINE |ID_IFN ,IFN_End_Of_Line}, + { REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character}, + { REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character}, + { REQ_UP_CHAR |ID_IFN ,IFN_Up_Character}, + { REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character}, + + { REQ_NEW_LINE |ID_FE ,FE_New_Line}, + { REQ_INS_CHAR |ID_FE ,FE_Insert_Character}, + { REQ_INS_LINE |ID_FE ,FE_Insert_Line}, + { REQ_DEL_CHAR |ID_FE ,FE_Delete_Character}, + { REQ_DEL_PREV |ID_FE ,FE_Delete_Previous}, + { REQ_DEL_LINE |ID_FE ,FE_Delete_Line}, + { REQ_DEL_WORD |ID_FE ,FE_Delete_Word}, + { REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line}, + { REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Form}, + { REQ_CLR_FIELD |ID_FE ,FE_Clear_Field}, + + { REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode}, + { REQ_INS_MODE |ID_EM ,EM_Insert_Mode}, + + { REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward}, + { REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward}, + { REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward}, + { REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward}, + { REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward}, + { REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward}, + + { REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward}, + { REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward}, + { REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward}, + { REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward}, + { REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward}, + { REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward}, + + { REQ_VALIDATION |ID_FV ,FV_Validation}, + + { REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice}, + { REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice} +}; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int form_driver(FORM * form,int c) +| +| Description : This is the workhorse of the forms system. It checks +| to determine whether the character c is a request or +| data. If it is a request, the form driver executes +| the request and returns the result. If it is data +| (printable character), it enters the data into the +| current position in the current field. If it is not +| recognized, the form driver assumes it is an application +| defined command and returns E_UNKNOWN_COMMAND. +| Application defined command should be defined relative +| to MAX_FORM_COMMAND, the maximum value of a request. +| +| Return Values : E_OK - success +| E_SYSTEM_ERROR - system error +| E_BAD_ARGUMENT - an argument is incorrect +| E_NOT_POSTED - form is not posted +| E_INVALID_FIELD - field contents are invalid +| E_BAD_STATE - called from inside a hook routine +| E_REQUEST_DENIED - request failed +| E_UNKNOWN_COMMAND - command not known ++--------------------------------------------------------------------------*/ +int form_driver(FORM * form, int c) +{ + const Binding_Info* BI = (Binding_Info *)0; + int res = E_UNKNOWN_COMMAND; + + if (!form) + RETURN(E_BAD_ARGUMENT); + + if (!(form->field)) + RETURN(E_NOT_CONNECTED); + + assert(form->page != 0); + + if (c==FIRST_ACTIVE_MAGIC) + { + form->current = _nc_First_Active_Field(form); + return E_OK; + } + + assert(form->current && + form->current->buf && + (form->current->form == form) + ); + + if ( form->status & _IN_DRIVER ) + RETURN(E_BAD_STATE); + + if ( !( form->status & _POSTED ) ) + RETURN(E_NOT_POSTED); + + if ((c>=MIN_FORM_COMMAND && c<=MAX_FORM_COMMAND) && + ((bindings[c-MIN_FORM_COMMAND].keycode & Key_Mask) == c)) + BI = &(bindings[c-MIN_FORM_COMMAND]); + + if (BI) + { + typedef int (*Generic_Method)(int (* const)(FORM *),FORM *); + static const Generic_Method Generic_Methods[] = + { + Page_Navigation, /* overloaded to call field&form hooks */ + Inter_Field_Navigation, /* overloaded to call field hooks */ + NULL, /* Intra-Field is generic */ + Vertical_Scrolling, /* Overloaded to check multi-line */ + Horizontal_Scrolling, /* Overloaded to check single-line */ + Field_Editing, /* Overloaded to mark modification */ + NULL, /* Edit Mode is generic */ + NULL, /* Field Validation is generic */ + NULL /* Choice Request is generic */ + }; + size_t nMethods = (sizeof(Generic_Methods)/sizeof(Generic_Methods[0])); + size_t method = ((BI->keycode & ID_Mask) >> ID_Shft) & 0xffff; + + if ( (method >= nMethods) || !(BI->cmd) ) + res = E_SYSTEM_ERROR; + else + { + Generic_Method fct = Generic_Methods[method]; + if (fct) + res = fct(BI->cmd,form); + else + res = (BI->cmd)(form); + } + } + else + { + if (!(c & (~(int)MAX_REGULAR_CHARACTER)) && + isprint((unsigned char)c) && + Check_Char(form->current->type,c, + (TypeArgument *)(form->current->arg))) + res = Data_Entry(form,c); + } + _nc_Refresh_Current_Field(form); + RETURN(res); +} + +/*---------------------------------------------------------------------------- + Field-Buffer manipulation routines. + The effects of setting a buffer is tightly coupled to the core of the form + driver logic. This is especially true in the case of growable fields. + So I don't separate this into an own module. + --------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_buffer(FIELD *field, +| int buffer, char *value) +| +| Description : Set the given buffer of the field to the given value. +| Buffer 0 stores the displayed content of the field. +| For dynamic fields this may grow the fieldbuffers if +| the length of the value exceeds the current buffer +| length. For buffer 0 only printable values are allowed. +| For static fields, the value needs not to be zero ter- +| minated. It is copied up to the length of the buffer. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid argument +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +int set_field_buffer(FIELD * field, int buffer, const char * value) +{ + char *s, *p; + int res = E_OK; + unsigned int len; + + if ( !field || !value || ((buffer < 0)||(buffer > field->nbuf)) ) + RETURN(E_BAD_ARGUMENT); + + len = Buffer_Length(field); + + if (buffer==0) + { + const char *v; + unsigned int i = 0; + + for(v=value; *v && (i<len); v++,i++) + { + if (!isprint((unsigned char)*v)) + RETURN(E_BAD_ARGUMENT); + } + } + + if (Growable(field)) + { + /* for a growable field we must assume zero terminated strings, because + somehow we have to detect the length of what should be copied. + */ + unsigned int vlen = strlen(value); + if (vlen > len) + { + if (!Field_Grown(field, + (int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols)))) + RETURN(E_SYSTEM_ERROR); + + /* in this case we also have to check, whether or not the remaining + characters in value are also printable for buffer 0. */ + if (buffer==0) + { + unsigned int i; + + for(i=len; i<vlen; i++) + if (!isprint((int)(value[i]))) + RETURN(E_BAD_ARGUMENT); + } + len = vlen; + } + } + + p = Address_Of_Nth_Buffer(field,buffer); + +#if HAVE_MEMCCPY + s = memccpy(p,value,0,len); +#else + for(s=(char *)value; *s && (s < (value+len)); s++) + p[s-value] = *s; + if (s < (value+len)) + { + int off = s-value; + p[off] = *s++; + s = p + (s-value); + } + else + s=(char *)0; +#endif + + if (s) + { /* this means, value was null terminated and not greater than the + buffer. We have to pad with blanks. Please note that due to memccpy + logic s points after the terminating null. */ + s--; /* now we point to the terminator. */ + assert(len >= (unsigned int)(s-p)); + if (len > (unsigned int)(s-p)) + memset(s,C_BLANK,len-(unsigned int)(s-p)); + } + + if (buffer==0) + { + int syncres; + if (((syncres=Synchronize_Field( field ))!=E_OK) && + (res==E_OK)) + res = syncres; + if (((syncres=Synchronize_Linked_Fields(field ))!=E_OK) && + (res==E_OK)) + res = syncres; + } + RETURN(res); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : char *field_buffer(const FIELD *field,int buffer) +| +| Description : Return the address of the buffer for the field. +| +| Return Values : Pointer to buffer or NULL if arguments were invalid. ++--------------------------------------------------------------------------*/ +char *field_buffer(const FIELD * field, int buffer) +{ + if (field && (buffer >= 0) && (buffer <= field->nbuf)) + return Address_Of_Nth_Buffer(field,buffer); + else + return (char *)0; +} + +/* frm_driver.c ends here */ diff --git a/Source/CursesDialog/form/frm_hook.c b/Source/CursesDialog/form/frm_hook.c new file mode 100644 index 0000000..eb654c4 --- /dev/null +++ b/Source/CursesDialog/form/frm_hook.c @@ -0,0 +1,140 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/* "Template" macro to generate function to set application specific hook */ +#define GEN_HOOK_SET_FUNCTION( typ, name ) \ +int set_ ## typ ## _ ## name (FORM *form, Form_Hook func)\ +{\ + (Normalize_Form( form ) -> typ ## name) = func ;\ + RETURN(E_OK);\ +} + +/* "Template" macro to generate function to get application specific hook */ +#define GEN_HOOK_GET_FUNCTION( typ, name ) \ +Form_Hook typ ## _ ## name ( const FORM *form )\ +{\ + return ( Normalize_Form( form ) -> typ ## name );\ +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_init(FORM *form, Form_Hook f) +| +| Description : Assigns an application defined initialization function +| to be called when the form is posted and just after +| the current field changes. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +GEN_HOOK_SET_FUNCTION(field,init) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : Form_Hook field_init(const FORM *form) +| +| Description : Retrieve field initialization routine address. +| +| Return Values : The address or NULL if no hook defined. ++--------------------------------------------------------------------------*/ +GEN_HOOK_GET_FUNCTION(field,init) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_field_term(FORM *form, Form_Hook f) +| +| Description : Assigns an application defined finalization function +| to be called when the form is unposted and just before +| the current field changes. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +GEN_HOOK_SET_FUNCTION(field,term) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : Form_Hook field_term(const FORM *form) +| +| Description : Retrieve field finalization routine address. +| +| Return Values : The address or NULL if no hook defined. ++--------------------------------------------------------------------------*/ +GEN_HOOK_GET_FUNCTION(field,term) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_form_init(FORM *form, Form_Hook f) +| +| Description : Assigns an application defined initialization function +| to be called when the form is posted and just after +| a page change. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +GEN_HOOK_SET_FUNCTION(form,init) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : Form_Hook form_init(const FORM *form) +| +| Description : Retrieve form initialization routine address. +| +| Return Values : The address or NULL if no hook defined. ++--------------------------------------------------------------------------*/ +GEN_HOOK_GET_FUNCTION(form,init) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_form_term(FORM *form, Form_Hook f) +| +| Description : Assigns an application defined finalization function +| to be called when the form is unposted and just before +| a page change. +| +| Return Values : E_OK - success ++--------------------------------------------------------------------------*/ +GEN_HOOK_SET_FUNCTION(form,term) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : Form_Hook form_term(const FORM *form) +| +| Description : Retrieve form finalization routine address. +| +| Return Values : The address or NULL if no hook defined. ++--------------------------------------------------------------------------*/ +GEN_HOOK_GET_FUNCTION(form,term) + +/* frm_hook.c ends here */ diff --git a/Source/CursesDialog/form/frm_opts.c b/Source/CursesDialog/form/frm_opts.c new file mode 100644 index 0000000..7bbeaa1 --- /dev/null +++ b/Source/CursesDialog/form/frm_opts.c @@ -0,0 +1,116 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_form_opts(FORM *form, Form_Options opts) +| +| Description : Turns on the named options and turns off all the +| remaining options for that form. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid options ++--------------------------------------------------------------------------*/ +int set_form_opts(FORM * form, Form_Options opts) +{ + opts &= ALL_FORM_OPTS; + if (opts & ~ALL_FORM_OPTS) + RETURN(E_BAD_ARGUMENT); + else + { + Normalize_Form( form )->opts = opts; + RETURN(E_OK); + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : Form_Options form_opts(const FORM *) +| +| Description : Retrieves the current form options. +| +| Return Values : The option flags. ++--------------------------------------------------------------------------*/ +Form_Options form_opts(const FORM * form) +{ + return (Normalize_Form(form)->opts & ALL_FORM_OPTS); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int form_opts_on(FORM *form, Form_Options opts) +| +| Description : Turns on the named options; no other options are +| changed. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid options ++--------------------------------------------------------------------------*/ +int form_opts_on(FORM * form, Form_Options opts) +{ + opts &= ALL_FORM_OPTS; + if (opts & ~ALL_FORM_OPTS) + RETURN(E_BAD_ARGUMENT); + else + { + Normalize_Form( form )->opts |= opts; + RETURN(E_OK); + } +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int form_opts_off(FORM *form, Form_Options opts) +| +| Description : Turns off the named options; no other options are +| changed. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid options ++--------------------------------------------------------------------------*/ +int form_opts_off(FORM * form, Form_Options opts) +{ + opts &= ALL_FORM_OPTS; + if (opts & ~ALL_FORM_OPTS) + RETURN(E_BAD_ARGUMENT); + else + { + Normalize_Form(form)->opts &= ~opts; + RETURN(E_OK); + } +} + +/* frm_opts.c ends here */ diff --git a/Source/CursesDialog/form/frm_page.c b/Source/CursesDialog/form/frm_page.c new file mode 100644 index 0000000..842cbce --- /dev/null +++ b/Source/CursesDialog/form/frm_page.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_form_page(FORM * form,int page) +| +| Description : Set the page number of the form. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid form pointer or page number +| E_BAD_STATE - called from a hook routine +| E_INVALID_FIELD - current field can't be left +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +int set_form_page(FORM * form, int page) +{ + int err = E_OK; + + if ( !form || (page<0) || (page>=form->maxpage) ) + RETURN(E_BAD_ARGUMENT); + + if (!(form->status & _POSTED)) + { + form->curpage = page; + form->current = _nc_First_Active_Field(form); + } + else + { + if (form->status & _IN_DRIVER) + err = E_BAD_STATE; + else + { + if (form->curpage != page) + { + if (!_nc_Internal_Validation(form)) + err = E_INVALID_FIELD; + else + { + Call_Hook(form,fieldterm); + Call_Hook(form,formterm); + err = _nc_Set_Form_Page(form,page,(FIELD *)0); + Call_Hook(form,forminit); + Call_Hook(form,fieldinit); + _nc_Refresh_Current_Field(form); + } + } + } + } + RETURN(err); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int form_page(const FORM * form) +| +| Description : Return the current page of the form. +| +| Return Values : >= 0 : current page number +| -1 : invalid form pointer ++--------------------------------------------------------------------------*/ +int form_page(const FORM * form) +{ + return Normalize_Form(form)->curpage; +} + +/* frm_page.c ends here */ diff --git a/Source/CursesDialog/form/frm_post.c b/Source/CursesDialog/form/frm_post.c new file mode 100644 index 0000000..fc0a359 --- /dev/null +++ b/Source/CursesDialog/form/frm_post.c @@ -0,0 +1,119 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int post_form(FORM * form) +| +| Description : Writes the form into its associated subwindow. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid form pointer +| E_POSTED - form already posted +| E_NOT_CONNECTED - no fields connected to form +| E_NO_ROOM - form doesn't fit into subwindow +| E_SYSTEM_ERROR - system error ++--------------------------------------------------------------------------*/ +int post_form(FORM * form) +{ + WINDOW *formwin; + int err; + int page; + int height, width; + + if (!form) + RETURN(E_BAD_ARGUMENT); + + if (form->status & _POSTED) + RETURN(E_POSTED); + + if (!(form->field)) + RETURN(E_NOT_CONNECTED); + + formwin = Get_Form_Window(form); + getmaxyx(formwin, height, width); + if ((form->cols > width) || (form->rows > height)) + RETURN(E_NO_ROOM); + + /* reset form->curpage to an invalid value. This forces Set_Form_Page + to do the page initialization which is required by post_form. + */ + page = form->curpage; + form->curpage = -1; + if ((err = _nc_Set_Form_Page(form,page,form->current))!=E_OK) + RETURN(err); + + form->status |= _POSTED; + + Call_Hook(form,forminit); + Call_Hook(form,fieldinit); + + _nc_Refresh_Current_Field(form); + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int unpost_form(FORM * form) +| +| Description : Erase form from its associated subwindow. +| +| Return Values : E_OK - success +| E_BAD_ARGUMENT - invalid form pointer +| E_NOT_POSTED - form isn't posted +| E_BAD_STATE - called from a hook routine ++--------------------------------------------------------------------------*/ +int unpost_form(FORM * form) +{ + if (!form) + RETURN(E_BAD_ARGUMENT); + + if (!(form->status & _POSTED)) + RETURN(E_NOT_POSTED); + + if (form->status & _IN_DRIVER) + RETURN(E_BAD_STATE); + + Call_Hook(form,fieldterm); + Call_Hook(form,formterm); + + werase(Get_Form_Window(form)); + delwin(form->w); + form->w = (WINDOW *)0; + form->status &= ~_POSTED; + RETURN(E_OK); +} + +/* frm_post.c ends here */ diff --git a/Source/CursesDialog/form/frm_req_name.c b/Source/CursesDialog/form/frm_req_name.c new file mode 100644 index 0000000..6fb9183 --- /dev/null +++ b/Source/CursesDialog/form/frm_req_name.c @@ -0,0 +1,163 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +/*************************************************************************** +* Module form_request_name * +* Routines to handle external names of menu requests * +***************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +static const char *request_names[ MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1 ] = { + "NEXT_PAGE" , + "PREV_PAGE" , + "FIRST_PAGE" , + "LAST_PAGE" , + + "NEXT_FIELD" , + "PREV_FIELD" , + "FIRST_FIELD" , + "LAST_FIELD" , + "SNEXT_FIELD" , + "SPREV_FIELD" , + "SFIRST_FIELD" , + "SLAST_FIELD" , + "LEFT_FIELD" , + "RIGHT_FIELD" , + "UP_FIELD" , + "DOWN_FIELD" , + + "NEXT_CHAR" , + "PREV_CHAR" , + "NEXT_LINE" , + "PREV_LINE" , + "NEXT_WORD" , + "PREV_WORD" , + "BEG_FIELD" , + "END_FIELD" , + "BEG_LINE" , + "END_LINE" , + "LEFT_CHAR" , + "RIGHT_CHAR" , + "UP_CHAR" , + "DOWN_CHAR" , + + "NEW_LINE" , + "INS_CHAR" , + "INS_LINE" , + "DEL_CHAR" , + "DEL_PREV" , + "DEL_LINE" , + "DEL_WORD" , + "CLR_EOL" , + "CLR_EOF" , + "CLR_FIELD" , + "OVL_MODE" , + "INS_MODE" , + "SCR_FLINE" , + "SCR_BLINE" , + "SCR_FPAGE" , + "SCR_BPAGE" , + "SCR_FHPAGE" , + "SCR_BHPAGE" , + "SCR_FCHAR" , + "SCR_BCHAR" , + "SCR_HFLINE" , + "SCR_HBLINE" , + "SCR_HFHALF" , + "SCR_HBHALF" , + + "VALIDATION" , + "NEXT_CHOICE" , + "PREV_CHOICE" +}; +#define A_SIZE (sizeof(request_names)/sizeof(request_names[0])) + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : const char * form_request_name (int request); +| +| Description : Get the external name of a form request. +| +| Return Values : Pointer to name - on success +| NULL - on invalid request code ++--------------------------------------------------------------------------*/ +const char *form_request_name( int request ) +{ + if ( (request < MIN_FORM_COMMAND) || (request > MAX_FORM_COMMAND) ) + { + SET_ERROR (E_BAD_ARGUMENT); + return (const char *)0; + } + else + return request_names[ request - MIN_FORM_COMMAND ]; +} + + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int form_request_by_name (const char *str); +| +| Description : Search for a request with this name. +| +| Return Values : Request Id - on success +| E_NO_MATCH - request not found ++--------------------------------------------------------------------------*/ +int form_request_by_name( const char *str ) +{ + /* because the table is so small, it doesn't really hurt + to run sequentially through it. + */ + unsigned int i = 0; + char buf[16]; + + if (str) + { + strncpy(buf,str,sizeof(buf)); + while( (i<sizeof(buf)) && (buf[i] != '\0') ) + { + buf[i] = toupper((int)(buf[i])); + i++; + } + + for (i=0; i < A_SIZE; i++) + { + if (strncmp(request_names[i],buf,sizeof(buf))==0) + return MIN_FORM_COMMAND + i; + } + } + RETURN(E_NO_MATCH); +} + +/* frm_req_name.c ends here */ diff --git a/Source/CursesDialog/form/frm_scale.c b/Source/CursesDialog/form/frm_scale.c new file mode 100644 index 0000000..028e9e2 --- /dev/null +++ b/Source/CursesDialog/form/frm_scale.c @@ -0,0 +1,63 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int scale_form( const FORM *form, int *rows, int *cols ) +| +| Description : Retrieve size of form +| +| Return Values : E_OK - no error +| E_BAD_ARGUMENT - invalid form pointer +| E_NOT_CONNECTED - no fields connected to form ++--------------------------------------------------------------------------*/ +int scale_form(const FORM * form, int * rows, int * cols) +{ + if ( !form ) + RETURN(E_BAD_ARGUMENT); + + if ( !(form->field) ) + RETURN(E_NOT_CONNECTED); + + if (rows) + *rows = form->rows; + if (cols) + *cols = form->cols; + + RETURN(E_OK); +} + +/* frm_scale.c ends here */ diff --git a/Source/CursesDialog/form/frm_sub.c b/Source/CursesDialog/form/frm_sub.c new file mode 100644 index 0000000..62dc613 --- /dev/null +++ b/Source/CursesDialog/form/frm_sub.c @@ -0,0 +1,69 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_form_sub(FORM *form, WINDOW *win) +| +| Description : Set the subwindow of the form to win. +| +| Return Values : E_OK - success +| E_POSTED - form is posted ++--------------------------------------------------------------------------*/ +int set_form_sub(FORM * form, WINDOW * win) +{ + if (form && (form->status & _POSTED)) + RETURN(E_POSTED); + + Normalize_Form( form )->sub = win; + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : WINDOW *form_sub(const FORM *) +| +| Description : Retrieve the window of the form. +| +| Return Values : The pointer to the Subwindow. ++--------------------------------------------------------------------------*/ +WINDOW *form_sub(const FORM * form) +{ + const FORM* f = Normalize_Form( form ); + return Get_Form_Window(f); +} + +/* frm_sub.c ends here */ diff --git a/Source/CursesDialog/form/frm_user.c b/Source/CursesDialog/form/frm_user.c new file mode 100644 index 0000000..f38bbbb --- /dev/null +++ b/Source/CursesDialog/form/frm_user.c @@ -0,0 +1,67 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_form_userptr(FORM *form, void *usrptr) +| +| Description : Set the pointer that is reserved in any form to store +| application relevant information +| +| Return Values : E_OK - on success ++--------------------------------------------------------------------------*/ +int set_form_userptr(FORM * form, void *usrptr) +{ + Normalize_Form(form)->usrptr = usrptr; + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : void *form_userptr(const FORM *form) +| +| Description : Return the pointer that is reserved in any form to +| store application relevant information. +| +| Return Values : Value of pointer. If no such pointer has been set, +| NULL is returned ++--------------------------------------------------------------------------*/ +void *form_userptr(const FORM * form) +{ + return Normalize_Form(form)->usrptr; +} + +/* frm_user.c ends here */ diff --git a/Source/CursesDialog/form/frm_win.c b/Source/CursesDialog/form/frm_win.c new file mode 100644 index 0000000..82d716f --- /dev/null +++ b/Source/CursesDialog/form/frm_win.c @@ -0,0 +1,70 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : int set_form_win(FORM *form,WINDOW *win) +| +| Description : Set the window of the form to win. +| +| Return Values : E_OK - success +| E_POSTED - form is posted ++--------------------------------------------------------------------------*/ +int set_form_win(FORM * form, WINDOW * win) +{ + if (form && (form->status & _POSTED)) + RETURN(E_POSTED); + + Normalize_Form( form )->win = win; + RETURN(E_OK); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : WINDOW *form_win(const FORM *) +| +| Description : Retrieve the window of the form. +| +| Return Values : The pointer to the Window or stdscr if there is none. ++--------------------------------------------------------------------------*/ +WINDOW *form_win(const FORM * form) +{ + const FORM* f = Normalize_Form( form ); + return (f->win ? f->win : stdscr); +} + +/* frm_win.c ends here */ + diff --git a/Source/CursesDialog/form/fty_alnum.c b/Source/CursesDialog/form/fty_alnum.c new file mode 100644 index 0000000..6f3cfd4 --- /dev/null +++ b/Source/CursesDialog/form/fty_alnum.c @@ -0,0 +1,138 @@ + +/* + * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT. + * You may freely copy it for use as a template for your own field types. + * If you develop a field type that might be of general use, please send + * it back to the ncurses maintainers for inclusion in the next version. + */ +/*************************************************************************** +* * +* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net * +* * +***************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +typedef struct { + int width; +} alnumARG; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Make_AlphaNumeric_Type(va_list *ap) +| +| Description : Allocate structure for alphanumeric type argument. +| +| Return Values : Pointer to argument structure or NULL on error ++--------------------------------------------------------------------------*/ +static void *Make_AlphaNumeric_Type(va_list * ap) +{ + alnumARG *argp = (alnumARG *)malloc(sizeof(alnumARG)); + + if (argp) + argp->width = va_arg(*ap,int); + + return ((void *)argp); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Copy_AlphaNumericType(const void *argp) +| +| Description : Copy structure for alphanumeric type argument. +| +| Return Values : Pointer to argument structure or NULL on error. ++--------------------------------------------------------------------------*/ +static void *Copy_AlphaNumeric_Type(const void *argp) +{ + const alnumARG *ap = (const alnumARG *)argp; + alnumARG *result = (alnumARG *)malloc(sizeof(alnumARG)); + + if (result) + *result = *ap; + + return ((void *)result); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Free_AlphaNumeric_Type(void *argp) +| +| Description : Free structure for alphanumeric type argument. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Free_AlphaNumeric_Type(void * argp) +{ + if (argp) + free(argp); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_AlphaNumeric_Field( +| FIELD *field, +| const void *argp) +| +| Description : Validate buffer content to be a valid alphanumeric value +| +| Return Values : TRUE - field is valid +| FALSE - field is invalid ++--------------------------------------------------------------------------*/ +static bool Check_AlphaNumeric_Field(FIELD * field, const void * argp) +{ + int width = ((const alnumARG *)argp)->width; + unsigned char *bp = (unsigned char *)field_buffer(field,0); + int l = -1; + unsigned char *s; + + while(*bp && *bp==' ') + bp++; + if (*bp) + { + s = bp; + while(*bp && isalnum(*bp)) + bp++; + l = (int)(bp-s); + while(*bp && *bp==' ') + bp++; + } + return ((*bp || (l < width)) ? FALSE : TRUE); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_AlphaNumeric_Character( +| int c, +| const void *argp ) +| +| Description : Check a character for the alphanumeric type. +| +| Return Values : TRUE - character is valid +| FALSE - character is invalid ++--------------------------------------------------------------------------*/ +static bool Check_AlphaNumeric_Character(int c, const void * argp) +{ + argp=0; /* Silence unused parameter warning. */ + return (isalnum(c) ? TRUE : FALSE); +} + +static FIELDTYPE typeALNUM = { + _HAS_ARGS | _RESIDENT, + 1, /* this is mutable, so we can't be const */ + (FIELDTYPE *)0, + (FIELDTYPE *)0, + Make_AlphaNumeric_Type, + Copy_AlphaNumeric_Type, + Free_AlphaNumeric_Type, + Check_AlphaNumeric_Field, + Check_AlphaNumeric_Character, + NULL, + NULL +}; + +FIELDTYPE* TYPE_ALNUM = &typeALNUM; + +/* fty_alnum.c ends here */ diff --git a/Source/CursesDialog/form/fty_alpha.c b/Source/CursesDialog/form/fty_alpha.c new file mode 100644 index 0000000..e4e9ceb --- /dev/null +++ b/Source/CursesDialog/form/fty_alpha.c @@ -0,0 +1,139 @@ + +/* + * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT. + * You may freely copy it for use as a template for your own field types. + * If you develop a field type that might be of general use, please send + * it back to the ncurses maintainers for inclusion in the next version. + */ +/*************************************************************************** +* * +* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net * +* * +***************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +typedef struct { + int width; +} alphaARG; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Make_Alpha_Type(va_list *ap) +| +| Description : Allocate structure for alpha type argument. +| +| Return Values : Pointer to argument structure or NULL on error ++--------------------------------------------------------------------------*/ +static void *Make_Alpha_Type(va_list * ap) +{ + alphaARG *argp = (alphaARG *)malloc(sizeof(alphaARG)); + if (argp) + { + argp->width = va_arg(*ap,int); + } + return ((void *)argp); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Copy_Alpha_Type(const void * argp) +| +| Description : Copy structure for alpha type argument. +| +| Return Values : Pointer to argument structure or NULL on error. ++--------------------------------------------------------------------------*/ +static void *Copy_Alpha_Type(const void * argp) +{ + const alphaARG *ap = (const alphaARG *)argp; + alphaARG *result = (alphaARG *)malloc(sizeof(alphaARG)); + + if (result) + { + *result = *ap; + } + return ((void *)result); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Free_Alpha_Type( void * argp ) +| +| Description : Free structure for alpha type argument. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Free_Alpha_Type(void * argp) +{ + if (argp) + free(argp); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_Alpha_Field( +| FIELD * field, +| const void * argp) +| +| Description : Validate buffer content to be a valid alpha value +| +| Return Values : TRUE - field is valid +| FALSE - field is invalid ++--------------------------------------------------------------------------*/ +static bool Check_Alpha_Field(FIELD * field, const void * argp) +{ + int width = ((const alphaARG *)argp)->width; + unsigned char *bp = (unsigned char *)field_buffer(field,0); + int l = -1; + unsigned char *s; + + while(*bp && *bp==' ') + bp++; + if (*bp) + { + s = bp; + while(*bp && isalpha(*bp)) + bp++; + l = (int)(bp-s); + while(*bp && *bp==' ') + bp++; + } + return ((*bp || (l < width)) ? FALSE : TRUE); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_Alpha_Character( +| int c, +| const void * argp) +| +| Description : Check a character for the alpha type. +| +| Return Values : TRUE - character is valid +| FALSE - character is invalid ++--------------------------------------------------------------------------*/ +static bool Check_Alpha_Character(int c, const void * argp) +{ + argp=0; /* Silence unused parameter warning. */ + return (isalpha(c) ? TRUE : FALSE); +} + +static FIELDTYPE typeALPHA = { + _HAS_ARGS | _RESIDENT, + 1, /* this is mutable, so we can't be const */ + (FIELDTYPE *)0, + (FIELDTYPE *)0, + Make_Alpha_Type, + Copy_Alpha_Type, + Free_Alpha_Type, + Check_Alpha_Field, + Check_Alpha_Character, + NULL, + NULL +}; + +FIELDTYPE* TYPE_ALPHA = &typeALPHA; + +/* fty_alpha.c ends here */ diff --git a/Source/CursesDialog/form/fty_enum.c b/Source/CursesDialog/form/fty_enum.c new file mode 100644 index 0000000..59058a9 --- /dev/null +++ b/Source/CursesDialog/form/fty_enum.c @@ -0,0 +1,295 @@ + +/* + * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT. + * You may freely copy it for use as a template for your own field types. + * If you develop a field type that might be of general use, please send + * it back to the ncurses maintainers for inclusion in the next version. + */ +/*************************************************************************** +* * +* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net * +* * +***************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +typedef struct { + char **kwds; + int count; + bool checkcase; + bool checkunique; +} enumARG; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Make_Enum_Type( va_list * ap ) +| +| Description : Allocate structure for enumeration type argument. +| +| Return Values : Pointer to argument structure or NULL on error ++--------------------------------------------------------------------------*/ +static void *Make_Enum_Type(va_list * ap) +{ + enumARG *argp = (enumARG *)malloc(sizeof(enumARG)); + + if (argp) + { + int cnt = 0; + char **kp = (char **)0; + int ccase, cunique; + + argp->kwds = va_arg(*ap,char **); + ccase = va_arg(*ap,int); + cunique = va_arg(*ap,int); + argp->checkcase = ccase ? TRUE : FALSE; + argp->checkunique = cunique ? TRUE : FALSE; + + kp = argp->kwds; + while( kp && (*kp++) ) cnt++; + argp->count = cnt; + } + return (void *)argp; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Copy_Enum_Type( const void * argp ) +| +| Description : Copy structure for enumeration type argument. +| +| Return Values : Pointer to argument structure or NULL on error. ++--------------------------------------------------------------------------*/ +static void *Copy_Enum_Type(const void * argp) +{ + enumARG *result = (enumARG *)0; + + if (argp) + { + const enumARG *ap = (const enumARG *)argp; + + result = (enumARG *)malloc(sizeof(enumARG)); + if (result) + *result = *ap; + } + return (void *)result; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Free_Enum_Type( void * argp ) +| +| Description : Free structure for enumeration type argument. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Free_Enum_Type(void * argp) +{ + if (argp) + free(argp); +} + +#define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++ +#define NOMATCH 0 +#define PARTIAL 1 +#define EXACT 2 + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static int Compare(const unsigned char * s, +| const unsigned char * buf, +| bool ccase ) +| +| Description : Check whether or not the text in 'buf' matches the +| text in 's', at least partial. +| +| Return Values : NOMATCH - buffer doesn't match +| PARTIAL - buffer matches partially +| EXACT - buffer matches exactly ++--------------------------------------------------------------------------*/ +static int Compare(const unsigned char *s, const unsigned char *buf, + bool ccase) +{ + SKIP_SPACE(buf); /* Skip leading spaces in both texts */ + SKIP_SPACE(s); + + if (*buf=='\0') + { + return (((*s)!='\0') ? NOMATCH : EXACT); + } + else + { + if (ccase) + { + while(*s++ == *buf) + { + if (*buf++=='\0') return EXACT; + } + } + else + { + while(toupper(*s++)==toupper(*buf)) + { + if (*buf++=='\0') return EXACT; + } + } + } + /* At this location buf points to the first character where it no longer + matches with s. So if only blanks are following, we have a partial + match otherwise there is no match */ + SKIP_SPACE(buf); + if (*buf) + return NOMATCH; + + /* If it happens that the reference buffer is at its end, the partial + match is actually an exact match. */ + return ((s[-1]!='\0') ? PARTIAL : EXACT); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_Enum_Field( +| FIELD * field, +| const void * argp) +| +| Description : Validate buffer content to be a valid enumeration value +| +| Return Values : TRUE - field is valid +| FALSE - field is invalid ++--------------------------------------------------------------------------*/ +static bool Check_Enum_Field(FIELD * field, const void * argp) +{ + char **kwds = ((const enumARG *)argp)->kwds; + bool ccase = ((const enumARG *)argp)->checkcase; + bool unique = ((const enumARG *)argp)->checkunique; + unsigned char *bp = (unsigned char *)field_buffer(field,0); + char *s, *t, *p; + int res; + + while( kwds && (s=(*kwds++)) ) + { + if ((res=Compare((unsigned char *)s,bp,ccase))!=NOMATCH) + { + p=t=s; /* t is at least a partial match */ + if ((unique && res!=EXACT)) + { + while( kwds && (p = *kwds++) ) + { + if ((res=Compare((unsigned char *)p,bp,ccase))!=NOMATCH) + { + if (res==EXACT) + { + t = p; + break; + } + else + t = (char *)0; + } + } + } + if (t) + { + set_field_buffer(field,0,t); + return TRUE; + } + if (!p) + break; + } + } + return FALSE; +} + +static const char *dummy[] = { (char *)0 }; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Next_Enum(FIELD * field, +| const void * argp) +| +| Description : Check for the next enumeration value +| +| Return Values : TRUE - next value found and loaded +| FALSE - no next value loaded ++--------------------------------------------------------------------------*/ +static bool Next_Enum(FIELD * field, const void * argp) +{ + const enumARG *args = (const enumARG *)argp; + char **kwds = args->kwds; + bool ccase = args->checkcase; + int cnt = args->count; + unsigned char *bp = (unsigned char *)field_buffer(field,0); + + if (kwds) { + while(cnt--) + { + if (Compare((unsigned char *)(*kwds++),bp,ccase)==EXACT) + break; + } + if (cnt<=0) + kwds = args->kwds; + if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT)) + { + set_field_buffer(field,0,*kwds); + return TRUE; + } + } + return FALSE; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Previous_Enum( +| FIELD * field, +| const void * argp) +| +| Description : Check for the previous enumeration value +| +| Return Values : TRUE - previous value found and loaded +| FALSE - no previous value loaded ++--------------------------------------------------------------------------*/ +static bool Previous_Enum(FIELD * field, const void * argp) +{ + const enumARG *args = (const enumARG *)argp; + int cnt = args->count; + char **kwds = &args->kwds[cnt-1]; + bool ccase = args->checkcase; + unsigned char *bp = (unsigned char *)field_buffer(field,0); + + if (kwds) { + while(cnt--) + { + if (Compare((unsigned char *)(*kwds--),bp,ccase)==EXACT) + break; + } + + if (cnt<=0) + kwds = &args->kwds[args->count-1]; + + if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT)) + { + set_field_buffer(field,0,*kwds); + return TRUE; + } + } + return FALSE; +} + + +static FIELDTYPE typeENUM = { + _HAS_ARGS | _HAS_CHOICE | _RESIDENT, + 1, /* this is mutable, so we can't be const */ + (FIELDTYPE *)0, + (FIELDTYPE *)0, + Make_Enum_Type, + Copy_Enum_Type, + Free_Enum_Type, + Check_Enum_Field, + NULL, + Next_Enum, + Previous_Enum +}; + +FIELDTYPE* TYPE_ENUM = &typeENUM; + +/* fty_enum.c ends here */ diff --git a/Source/CursesDialog/form/fty_int.c b/Source/CursesDialog/form/fty_int.c new file mode 100644 index 0000000..7107fcc --- /dev/null +++ b/Source/CursesDialog/form/fty_int.c @@ -0,0 +1,161 @@ + +/* + * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT. + * You may freely copy it for use as a template for your own field types. + * If you develop a field type that might be of general use, please send + * it back to the ncurses maintainers for inclusion in the next version. + */ +/*************************************************************************** +* * +* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net * +* * +***************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +typedef struct { + int precision; + long low; + long high; +} integerARG; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Make_Integer_Type( va_list * ap ) +| +| Description : Allocate structure for integer type argument. +| +| Return Values : Pointer to argument structure or NULL on error ++--------------------------------------------------------------------------*/ +static void *Make_Integer_Type(va_list * ap) +{ + integerARG *argp = (integerARG *)malloc(sizeof(integerARG)); + + if (argp) + { + argp->precision = va_arg(*ap,int); + argp->low = va_arg(*ap,long); + argp->high = va_arg(*ap,long); + } + return (void *)argp; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Copy_Integer_Type(const void * argp) +| +| Description : Copy structure for integer type argument. +| +| Return Values : Pointer to argument structure or NULL on error. ++--------------------------------------------------------------------------*/ +static void *Copy_Integer_Type(const void * argp) +{ + const integerARG *ap = (const integerARG *)argp; + integerARG *result = (integerARG *)0; + + if (argp) + { + result = (integerARG *)malloc(sizeof(integerARG)); + if (result) + *result = *ap; + } + return (void *)result; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Free_Integer_Type(void * argp) +| +| Description : Free structure for integer type argument. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Free_Integer_Type(void * argp) +{ + if (argp) + free(argp); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_Integer_Field( +| FIELD * field, +| const void * argp) +| +| Description : Validate buffer content to be a valid integer value +| +| Return Values : TRUE - field is valid +| FALSE - field is invalid ++--------------------------------------------------------------------------*/ +static bool Check_Integer_Field(FIELD * field, const void * argp) +{ + const integerARG *argi = (const integerARG *)argp; + long low = argi->low; + long high = argi->high; + int prec = argi->precision; + unsigned char *bp = (unsigned char *)field_buffer(field,0); + char *s = (char *)bp; + long val; + char buf[100]; + + while( *bp && *bp==' ') bp++; + if (*bp) + { + if (*bp=='-') bp++; + while (*bp) + { + if (!isdigit(*bp)) break; + bp++; + } + while(*bp && *bp==' ') bp++; + if (*bp=='\0') + { + val = atol(s); + if (low<high) + { + if (val<low || val>high) return FALSE; + } + sprintf(buf,"%.*ld",(prec>0?prec:0),val); + set_field_buffer(field,0,buf); + return TRUE; + } + } + return FALSE; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_Integer_Character( +| int c, +| const void * argp) +| +| Description : Check a character for the integer type. +| +| Return Values : TRUE - character is valid +| FALSE - character is invalid ++--------------------------------------------------------------------------*/ +static bool Check_Integer_Character(int c, const void * argp) +{ + argp=0; /* Silence unused parameter warning. */ + return ((isdigit(c) || (c=='-')) ? TRUE : FALSE); +} + +static FIELDTYPE typeINTEGER = { + _HAS_ARGS | _RESIDENT, + 1, /* this is mutable, so we can't be const */ + (FIELDTYPE *)0, + (FIELDTYPE *)0, + Make_Integer_Type, + Copy_Integer_Type, + Free_Integer_Type, + Check_Integer_Field, + Check_Integer_Character, + NULL, + NULL +}; + +FIELDTYPE* TYPE_INTEGER = &typeINTEGER; + +/* fty_int.c ends here */ diff --git a/Source/CursesDialog/form/fty_ipv4.c b/Source/CursesDialog/form/fty_ipv4.c new file mode 100644 index 0000000..c855af6 --- /dev/null +++ b/Source/CursesDialog/form/fty_ipv4.c @@ -0,0 +1,84 @@ + +/* + * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT. + * You may freely copy it for use as a template for your own field types. + * If you develop a field type that might be of general use, please send + * it back to the ncurses maintainers for inclusion in the next version. + */ +/*************************************************************************** +* * +* Author : Per Foreby, perf@efd.lth.se * +* * +***************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_IPV4_Field( +| FIELD * field, +| const void * argp) +| +| Description : Validate buffer content to be a valid IP number (Ver. 4) +| +| Return Values : TRUE - field is valid +| FALSE - field is invalid ++--------------------------------------------------------------------------*/ +static bool Check_IPV4_Field(FIELD * field, const void * argp) +{ + char *bp = field_buffer(field,0); + int num = 0, len; + unsigned int d1=256, d2=256, d3=256, d4=256; + + argp=0; /* Silence unused parameter warning. */ + + if(isdigit((int)(*bp))) /* Must start with digit */ + { + num = sscanf(bp, "%u.%u.%u.%u%n", &d1, &d2, &d3, &d4, &len); + if (num == 4) + { + bp += len; /* Make bp point to what sscanf() left */ + while (*bp && isspace((int)(*bp))) + bp++; /* Allow trailing whitespace */ + } + } + return ((num != 4 || *bp || d1 > 255 || d2 > 255 + || d3 > 255 || d4 > 255) ? FALSE : TRUE); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_IPV4_Character( +| int c, +| const void *argp ) +| +| Description : Check a character for unsigned type or period. +| +| Return Values : TRUE - character is valid +| FALSE - character is invalid ++--------------------------------------------------------------------------*/ +static bool Check_IPV4_Character(int c, const void * argp) +{ + argp=0; /* Silence unused parameter warning. */ + return ((isdigit(c) || (c=='.')) ? TRUE : FALSE); +} + +static FIELDTYPE typeIPV4 = { + _RESIDENT, + 1, /* this is mutable, so we can't be const */ + (FIELDTYPE *)0, + (FIELDTYPE *)0, + NULL, + NULL, + NULL, + Check_IPV4_Field, + Check_IPV4_Character, + NULL, + NULL +}; + +FIELDTYPE* TYPE_IPV4 = &typeIPV4; + +/* fty_ipv4.c ends here */ diff --git a/Source/CursesDialog/form/fty_num.c b/Source/CursesDialog/form/fty_num.c new file mode 100644 index 0000000..7809599 --- /dev/null +++ b/Source/CursesDialog/form/fty_num.c @@ -0,0 +1,192 @@ + +/* + * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT. + * You may freely copy it for use as a template for your own field types. + * If you develop a field type that might be of general use, please send + * it back to the ncurses maintainers for inclusion in the next version. + */ +/*************************************************************************** +* * +* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net * +* * +***************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +#if HAVE_LOCALE_H +#include <locale.h> +#endif + +typedef struct { + int precision; + double low; + double high; + struct lconv* L; +} numericARG; + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Make_Numeric_Type(va_list * ap) +| +| Description : Allocate structure for numeric type argument. +| +| Return Values : Pointer to argument structure or NULL on error ++--------------------------------------------------------------------------*/ +static void *Make_Numeric_Type(va_list * ap) +{ + numericARG *argn = (numericARG *)malloc(sizeof(numericARG)); + + if (argn) + { + argn->precision = va_arg(*ap,int); + argn->low = va_arg(*ap,double); + argn->high = va_arg(*ap,double); +#if HAVE_LOCALE_H + argn->L = localeconv(); +#else + argn->L = NULL; +#endif + } + return (void *)argn; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Copy_Numeric_Type(const void * argp) +| +| Description : Copy structure for numeric type argument. +| +| Return Values : Pointer to argument structure or NULL on error. ++--------------------------------------------------------------------------*/ +static void *Copy_Numeric_Type(const void * argp) +{ + const numericARG *ap = (const numericARG *)argp; + numericARG *result = (numericARG *)0; + + if (argp) + { + result = (numericARG *)malloc(sizeof(numericARG)); + if (result) + *result = *ap; + } + return (void *)result; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Free_Numeric_Type(void * argp) +| +| Description : Free structure for numeric type argument. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Free_Numeric_Type(void * argp) +{ + if (argp) + free(argp); +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_Numeric_Field(FIELD * field, +| const void * argp) +| +| Description : Validate buffer content to be a valid numeric value +| +| Return Values : TRUE - field is valid +| FALSE - field is invalid ++--------------------------------------------------------------------------*/ +static bool Check_Numeric_Field(FIELD * field, const void * argp) +{ + const numericARG *argn = (const numericARG *)argp; + double low = argn->low; + double high = argn->high; + int prec = argn->precision; + unsigned char *bp = (unsigned char *)field_buffer(field,0); + char *s = (char *)bp; + double val = 0.0; + char buf[64]; + + while(*bp && *bp==' ') bp++; + if (*bp) + { + if (*bp=='-' || *bp=='+') + bp++; + while(*bp) + { + if (!isdigit(*bp)) break; + bp++; + } + if (*bp==( +#if HAVE_LOCALE_H + (L && L->decimal_point) ? *(L->decimal_point) : +#endif + '.')) + { + bp++; + while(*bp) + { + if (!isdigit(*bp)) break; + bp++; + } + } + while(*bp && *bp==' ') bp++; + if (*bp=='\0') + { + val = atof(s); + if (low<high) + { + if (val<low || val>high) return FALSE; + } + sprintf(buf,"%.*f",(prec>0?prec:0),val); + set_field_buffer(field,0,buf); + return TRUE; + } + } + return FALSE; +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_Numeric_Character( +| int c, +| const void * argp) +| +| Description : Check a character for the numeric type. +| +| Return Values : TRUE - character is valid +| FALSE - character is invalid ++--------------------------------------------------------------------------*/ +static bool Check_Numeric_Character(int c, const void * argp) +{ + argp=0; /* Silence unused parameter warning. */ + return (isdigit(c) || + c == '+' || + c == '-' || + c == ( +#if HAVE_LOCALE_H + (L && L->decimal_point) ? *(L->decimal_point) : +#endif + '.') + ) ? TRUE : FALSE; +} + +static FIELDTYPE typeNUMERIC = { + _HAS_ARGS | _RESIDENT, + 1, /* this is mutable, so we can't be const */ + (FIELDTYPE *)0, + (FIELDTYPE *)0, + Make_Numeric_Type, + Copy_Numeric_Type, + Free_Numeric_Type, + Check_Numeric_Field, + Check_Numeric_Character, + NULL, + NULL +}; + +FIELDTYPE* TYPE_NUMERIC = &typeNUMERIC; + +/* fty_num.c ends here */ diff --git a/Source/CursesDialog/form/fty_regex.c b/Source/CursesDialog/form/fty_regex.c new file mode 100644 index 0000000..f90e0c1 --- /dev/null +++ b/Source/CursesDialog/form/fty_regex.c @@ -0,0 +1,264 @@ + +/* + * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT. + * You may freely copy it for use as a template for your own field types. + * If you develop a field type that might be of general use, please send + * it back to the ncurses maintainers for inclusion in the next version. + */ +/*************************************************************************** +* * +* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net * +* * +***************************************************************************/ + +#include "form.priv.h" + +MODULE_ID("$Id$") + +#if HAVE_REGEX_H_FUNCS /* We prefer POSIX regex */ +#include <regex.h> + +typedef struct +{ + regex_t *pRegExp; + unsigned long *refCount; +} RegExp_Arg; + +#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS +#undef RETURN +static int reg_errno; + +static char *RegEx_Init(char *instring) +{ + reg_errno = 0; + return instring; +} + +static char *RegEx_Error(int code) +{ + reg_errno = code; + return 0; +} + +#define INIT char *sp = RegEx_Init(instring); +#define GETC() (*sp++) +#define PEEKC() (*sp) +#define UNGETC(c) (--sp) +#define RETURN(c) return(c) +#define ERROR(c) return RegEx_Error(c) + +#if HAVE_REGEXP_H_FUNCS +#include <regexp.h> +#else +#include <regexpr.h> +#endif + +typedef struct +{ + char *compiled_expression; + unsigned long *refCount; +} RegExp_Arg; + +/* Maximum Length we allow for a compiled regular expression */ +#define MAX_RX_LEN (2048) +#define RX_INCREMENT (256) + +#endif + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Make_RegularExpression_Type(va_list * ap) +| +| Description : Allocate structure for regex type argument. +| +| Return Values : Pointer to argument structure or NULL on error ++--------------------------------------------------------------------------*/ +static void *Make_RegularExpression_Type(va_list * ap) +{ +#if HAVE_REGEX_H_FUNCS + char *rx = va_arg(*ap,char *); + RegExp_Arg *preg; + + preg = (RegExp_Arg*)malloc(sizeof(RegExp_Arg)); + if (preg) + { + if (((preg->pRegExp = (regex_t*)malloc(sizeof(regex_t))) != (regex_t*)0) + && !regcomp(preg->pRegExp,rx, + (REG_EXTENDED | REG_NOSUB | REG_NEWLINE) )) + { + preg->refCount = (unsigned long *)malloc(sizeof(unsigned long)); + *(preg->refCount) = 1; + } + else + { + if (preg->pRegExp) + free(preg->pRegExp); + free(preg); + preg = (RegExp_Arg*)0; + } + } + return((void *)preg); +#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS + char *rx = va_arg(*ap,char *); + RegExp_Arg *pArg; + + pArg = (RegExp_Arg *)malloc(sizeof(RegExp_Arg)); + + if (pArg) + { + int blen = RX_INCREMENT; + pArg->compiled_expression = NULL; + pArg->refCount = (unsigned long *)malloc(sizeof(unsigned long)); + *(pArg->refCount) = 1; + + do { + char *buf = (char *)malloc(blen); + if (buf) + { +#if HAVE_REGEXP_H_FUNCS + char *last_pos = compile (rx, buf, &buf[blen], '\0'); +#else /* HAVE_REGEXPR_H_FUNCS */ + char *last_pos = compile (rx, buf, &buf[blen]); +#endif + if (reg_errno) + { + free(buf); + if (reg_errno==50) + blen += RX_INCREMENT; + else + { + free(pArg); + pArg = NULL; + break; + } + } + else + { + pArg->compiled_expression = buf; + break; + } + } + } while( blen <= MAX_RX_LEN ); + } + if (pArg && !pArg->compiled_expression) + { + free(pArg); + pArg = NULL; + } + return (void *)pArg; +#else + ap=0; /* Silence unused parameter warning. */ + return 0; +#endif +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void *Copy_RegularExpression_Type( +| const void * argp) +| +| Description : Copy structure for regex type argument. +| +| Return Values : Pointer to argument structure or NULL on error. ++--------------------------------------------------------------------------*/ +static void *Copy_RegularExpression_Type(const void * argp) +{ +#if (HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS) + const RegExp_Arg *ap = (const RegExp_Arg *)argp; + const RegExp_Arg *result = (const RegExp_Arg *)0; + + if (ap) + { + *(ap->refCount) += 1; + result = ap; + } + return (void *)result; +#else + argp=0; /* Silence unused parameter warning. */ + return 0; +#endif +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static void Free_RegularExpression_Type(void * argp) +| +| Description : Free structure for regex type argument. +| +| Return Values : - ++--------------------------------------------------------------------------*/ +static void Free_RegularExpression_Type(void * argp) +{ +#if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS + RegExp_Arg *ap = (RegExp_Arg *)argp; + if (ap) + { + if (--(*(ap->refCount)) == 0) + { +#if HAVE_REGEX_H_FUNCS + if (ap->pRegExp) + { + free(ap->refCount); + regfree(ap->pRegExp); + } +#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS + if (ap->compiled_expression) + { + free(ap->refCount); + free(ap->compiled_expression); + } +#endif + free(ap); + } + } +#else + argp=0; /* Silence unused parameter warning. */ +#endif +} + +/*--------------------------------------------------------------------------- +| Facility : libnform +| Function : static bool Check_RegularExpression_Field( +| FIELD * field, +| const void * argp) +| +| Description : Validate buffer content to be a valid regular expression +| +| Return Values : TRUE - field is valid +| FALSE - field is invalid ++--------------------------------------------------------------------------*/ +static bool Check_RegularExpression_Field(FIELD * field, const void * argp) +{ + bool match = FALSE; +#if HAVE_REGEX_H_FUNCS + const RegExp_Arg *ap = (const RegExp_Arg*)argp; + if (ap && ap->pRegExp) + match = (regexec(ap->pRegExp,field_buffer(field,0),0,NULL,0) ? FALSE:TRUE); +#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS + RegExp_Arg *ap = (RegExp_Arg *)argp; + if (ap && ap->compiled_expression) + match = (step(field_buffer(field,0),ap->compiled_expression) ? TRUE:FALSE); +#else + argp=0; /* Silence unused parameter warning. */ + field=0; /* Silence unused parameter warning. */ +#endif + return match; +} + +static FIELDTYPE typeREGEXP = { + _HAS_ARGS | _RESIDENT, + 1, /* this is mutable, so we can't be const */ + (FIELDTYPE *)0, + (FIELDTYPE *)0, + Make_RegularExpression_Type, + Copy_RegularExpression_Type, + Free_RegularExpression_Type, + Check_RegularExpression_Field, + NULL, + NULL, + NULL +}; + +FIELDTYPE* TYPE_REGEXP = &typeREGEXP; + +/* fty_regex.c ends here */ diff --git a/Source/CursesDialog/form/llib-lform b/Source/CursesDialog/form/llib-lform new file mode 100644 index 0000000..ac2ba43 --- /dev/null +++ b/Source/CursesDialog/form/llib-lform @@ -0,0 +1,694 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Thomas E. Dickey <dickey@clark.net> 1996,1997 * + ****************************************************************************/ +/* LINTLIBRARY */ + +/* ./fld_arg.c */ + +#include "form.priv.h" + +#undef set_fieldtype_arg +int set_fieldtype_arg( + FIELDTYPE *typ, + void *(*const make_arg)( + va_list *p1), + void *(*const copy_arg)( + const void *p1), + void (*const free_arg)( + void *p1)) + { return(*(int *)0); } + +#undef field_arg +void *field_arg( + const FIELD *field) + { return(*(void **)0); } + +/* ./fld_attr.c */ + +#undef set_field_fore +int set_field_fore( + FIELD *field, + chtype attr) + { return(*(int *)0); } + +#undef field_fore +chtype field_fore( + const FIELD *field) + { return(*(chtype *)0); } + +#undef set_field_back +int set_field_back( + FIELD *field, + chtype attr) + { return(*(int *)0); } + +#undef field_back +chtype field_back( + const FIELD *field) + { return(*(chtype *)0); } + +/* ./fld_current.c */ + +#undef set_current_field +int set_current_field( + FORM *form, + FIELD *field) + { return(*(int *)0); } + +#undef current_field +FIELD *current_field( + const FORM *form) + { return(*(FIELD **)0); } + +#undef field_index +int field_index( + const FIELD *field) + { return(*(int *)0); } + +/* ./fld_def.c */ + +#undef _nc_Default_Field +FIELD *_nc_Default_Field; + +#undef _nc_Make_Argument +TypeArgument *_nc_Make_Argument( + const FIELDTYPE *typ, + va_list *ap, + int *err) + { return(*(TypeArgument **)0); } + +#undef _nc_Copy_Argument +TypeArgument *_nc_Copy_Argument( + const FIELDTYPE *typ, + const TypeArgument *argp, + int *err) + { return(*(TypeArgument **)0); } + +#undef _nc_Free_Argument +void _nc_Free_Argument( + const FIELDTYPE *typ, + TypeArgument *argp) + { /* void */ } + +#undef _nc_Copy_Type +bool _nc_Copy_Type( + FIELD *dst, + FIELD const *src) + { return(*(bool *)0); } + +#undef _nc_Free_Type +void _nc_Free_Type( + FIELD *field) + { /* void */ } + +#undef new_field +FIELD *new_field( + int rows, + int cols, + int frow, + int fcol, + int nrow, + int nbuf) + { return(*(FIELD **)0); } + +#undef free_field +int free_field( + FIELD *field) + { return(*(int *)0); } + +/* ./fld_dup.c */ + +#undef dup_field +FIELD *dup_field( + FIELD *field, + int frow, + int fcol) + { return(*(FIELD **)0); } + +/* ./fld_ftchoice.c */ + +#undef set_fieldtype_choice +int set_fieldtype_choice( + FIELDTYPE *typ, + bool (*const next_choice)( + FIELD *p1, + const void *p2), + bool (*const prev_choice)( + FIELD *p1, + const void *p2)) + { return(*(int *)0); } + +/* ./fld_ftlink.c */ + +#undef link_fieldtype +FIELDTYPE *link_fieldtype( + FIELDTYPE *type1, + FIELDTYPE *type2) + { return(*(FIELDTYPE **)0); } + +/* ./fld_info.c */ + +#undef field_info +int field_info( + const FIELD *field, + int *rows, + int *cols, + int *frow, + int *fcol, + int *nrow, + int *nbuf) + { return(*(int *)0); } + +#undef dynamic_field_info +int dynamic_field_info( + const FIELD *field, + int *drows, + int *dcols, + int *maxgrow) + { return(*(int *)0); } + +/* ./fld_just.c */ + +#undef set_field_just +int set_field_just( + FIELD *field, + int just) + { return(*(int *)0); } + +#undef field_just +int field_just( + const FIELD *field) + { return(*(int *)0); } + +/* ./fld_link.c */ + +#undef link_field +FIELD *link_field( + FIELD *field, + int frow, + int fcol) + { return(*(FIELD **)0); } + +/* ./fld_max.c */ + +#undef set_max_field +int set_max_field( + FIELD *field, + int maxgrow) + { return(*(int *)0); } + +/* ./fld_move.c */ + +#undef move_field +int move_field( + FIELD *field, + int frow, + int fcol) + { return(*(int *)0); } + +/* ./fld_newftyp.c */ + +#undef _nc_Default_FieldType +const FIELDTYPE *_nc_Default_FieldType = {0}; + +#undef new_fieldtype +FIELDTYPE *new_fieldtype( + bool (*const field_check)( + FIELD *p1, + const void *p2), + bool (*const char_check)( + int p1, + const void *p2)) + { return(*(FIELDTYPE **)0); } + +#undef free_fieldtype +int free_fieldtype( + FIELDTYPE *typ) + { return(*(int *)0); } + +/* ./fld_opts.c */ + +#undef set_field_opts +int set_field_opts( + FIELD *field, + Field_Options opts) + { return(*(int *)0); } + +#undef field_opts +Field_Options field_opts( + const FIELD *field) + { return(*(Field_Options *)0); } + +#undef field_opts_on +int field_opts_on( + FIELD *field, + Field_Options opts) + { return(*(int *)0); } + +#undef field_opts_off +int field_opts_off( + FIELD *field, + Field_Options opts) + { return(*(int *)0); } + +/* ./fld_pad.c */ + +#undef set_field_pad +int set_field_pad( + FIELD *field, + int ch) + { return(*(int *)0); } + +#undef field_pad +int field_pad( + const FIELD *field) + { return(*(int *)0); } + +/* ./fld_page.c */ + +#undef set_new_page +int set_new_page( + FIELD *field, + bool new_page_flag) + { return(*(int *)0); } + +#undef new_page +bool new_page( + const FIELD *field) + { return(*(bool *)0); } + +/* ./fld_stat.c */ + +#undef set_field_status +int set_field_status( + FIELD *field, + bool status) + { return(*(int *)0); } + +#undef field_status +bool field_status( + const FIELD *field) + { return(*(bool *)0); } + +/* ./fld_type.c */ + +#undef set_field_type +int set_field_type( + FIELD *field, + FIELDTYPE *type, + ...) + { return(*(int *)0); } + +#undef field_type +FIELDTYPE *field_type( + const FIELD *field) + { return(*(FIELDTYPE **)0); } + +/* ./fld_user.c */ + +#undef set_field_userptr +int set_field_userptr( + FIELD *field, + void *usrptr) + { return(*(int *)0); } + +#undef field_userptr +void *field_userptr( + const FIELD *field) + { return(*(void **)0); } + +/* ./frm_cursor.c */ + +#undef pos_form_cursor +int pos_form_cursor( + FORM *form) + { return(*(int *)0); } + +/* ./frm_data.c */ + +#undef data_behind +bool data_behind( + const FORM *form) + { return(*(bool *)0); } + +#undef data_ahead +bool data_ahead( + const FORM *form) + { return(*(bool *)0); } + +/* ./frm_def.c */ + +#undef _nc_Default_Form +FORM *_nc_Default_Form; + +#undef new_form +FORM *new_form( + FIELD **fields) + { return(*(FORM **)0); } + +#undef free_form +int free_form( + FORM *form) + { return(*(int *)0); } + +#undef set_form_fields +int set_form_fields( + FORM *form, + FIELD **fields) + { return(*(int *)0); } + +#undef form_fields +FIELD **form_fields( + const FORM *form) + { return(*(FIELD ***)0); } + +#undef field_count +int field_count( + const FORM *form) + { return(*(int *)0); } + +/* ./frm_driver.c */ + +#undef _nc_Position_Form_Cursor +int _nc_Position_Form_Cursor( + FORM *form) + { return(*(int *)0); } + +#undef _nc_Refresh_Current_Field +int _nc_Refresh_Current_Field( + FORM *form) + { return(*(int *)0); } + +#undef _nc_Synchronize_Attributes +int _nc_Synchronize_Attributes( + FIELD *field) + { return(*(int *)0); } + +#undef _nc_Synchronize_Options +int _nc_Synchronize_Options( + FIELD *field, + Field_Options newopts) + { return(*(int *)0); } + +#undef _nc_Set_Current_Field +int _nc_Set_Current_Field( + FORM *form, + FIELD *newfield) + { return(*(int *)0); } + +#undef _nc_Internal_Validation +bool _nc_Internal_Validation( + FORM *form) + { return(*(bool *)0); } + +#undef _nc_First_Active_Field +FIELD *_nc_First_Active_Field( + FORM *form) + { return(*(FIELD **)0); } + +#undef _nc_Set_Form_Page +int _nc_Set_Form_Page( + FORM *form, + int page, + FIELD *field) + { return(*(int *)0); } + +typedef struct { + int keycode; + int (*cmd)(FORM *); +} Binding_Info; + +#undef form_driver +int form_driver( + FORM *form, + int c) + { return(*(int *)0); } + +#undef set_field_buffer +int set_field_buffer( + FIELD *field, + int buffer, + const char *value) + { return(*(int *)0); } + +#undef field_buffer +char *field_buffer( + const FIELD *field, + int buffer) + { return(*(char **)0); } + +/* ./frm_hook.c */ + +#undef set_field_init +int set_field_init( + FORM *form, + Form_Hook func) + { return(*(int *)0); } + +#undef field_init +Form_Hook field_init( + const FORM *form) + { return(*(Form_Hook *)0); } + +#undef set_field_term +int set_field_term( + FORM *form, + Form_Hook func) + { return(*(int *)0); } + +#undef field_term +Form_Hook field_term( + const FORM *form) + { return(*(Form_Hook *)0); } + +#undef set_form_init +int set_form_init( + FORM *form, + Form_Hook func) + { return(*(int *)0); } + +#undef form_init +Form_Hook form_init( + const FORM *form) + { return(*(Form_Hook *)0); } + +#undef set_form_term +int set_form_term( + FORM *form, + Form_Hook func) + { return(*(int *)0); } + +#undef form_term +Form_Hook form_term( + const FORM *form) + { return(*(Form_Hook *)0); } + +/* ./frm_opts.c */ + +#undef set_form_opts +int set_form_opts( + FORM *form, + Form_Options opts) + { return(*(int *)0); } + +#undef form_opts +Form_Options form_opts( + const FORM *form) + { return(*(Form_Options *)0); } + +#undef form_opts_on +int form_opts_on( + FORM *form, + Form_Options opts) + { return(*(int *)0); } + +#undef form_opts_off +int form_opts_off( + FORM *form, + Form_Options opts) + { return(*(int *)0); } + +/* ./frm_page.c */ + +#undef set_form_page +int set_form_page( + FORM *form, + int page) + { return(*(int *)0); } + +#undef form_page +int form_page( + const FORM *form) + { return(*(int *)0); } + +/* ./frm_post.c */ + +#undef post_form +int post_form( + FORM *form) + { return(*(int *)0); } + +#undef unpost_form +int unpost_form( + FORM *form) + { return(*(int *)0); } + +/* ./frm_req_name.c */ + +#undef form_request_name +const char *form_request_name( + int request) + { return(*(const char **)0); } + +#undef form_request_by_name +int form_request_by_name( + const char *str) + { return(*(int *)0); } + +/* ./frm_scale.c */ + +#undef scale_form +int scale_form( + const FORM *form, + int *rows, + int *cols) + { return(*(int *)0); } + +/* ./frm_sub.c */ + +#undef set_form_sub +int set_form_sub( + FORM *form, + WINDOW *win) + { return(*(int *)0); } + +#undef form_sub +WINDOW *form_sub( + const FORM *form) + { return(*(WINDOW **)0); } + +/* ./frm_user.c */ + +#undef set_form_userptr +int set_form_userptr( + FORM *form, + void *usrptr) + { return(*(int *)0); } + +#undef form_userptr +void *form_userptr( + const FORM *form) + { return(*(void **)0); } + +/* ./frm_win.c */ + +#undef set_form_win +int set_form_win( + FORM *form, + WINDOW *win) + { return(*(int *)0); } + +#undef form_win +WINDOW *form_win( + const FORM *form) + { return(*(WINDOW **)0); } + +/* ./fty_alnum.c */ + +typedef struct { + int width; +} alnumARG; + +#undef TYPE_ALNUM +FIELDTYPE *TYPE_ALNUM; + +/* ./fty_alpha.c */ + +typedef struct { + int width; +} alphaARG; + +#undef TYPE_ALPHA +FIELDTYPE *TYPE_ALPHA; + +/* ./fty_enum.c */ + +typedef struct { + char **kwds; + int count; + bool checkcase; + bool checkunique; +} enumARG; + +#undef TYPE_ENUM +FIELDTYPE *TYPE_ENUM; + +/* ./fty_int.c */ + +typedef struct { + int precision; + long low; + long high; +} integerARG; + +#undef TYPE_INTEGER +FIELDTYPE *TYPE_INTEGER; + +/* ./fty_ipv4.c */ +#undef TYPE_IPV4 +FIELDTYPE *TYPE_IPV4; + +/* ./fty_num.c */ + +#include <locale.h> + +typedef struct { + int precision; + double low; + double high; + struct lconv* L; +} numericARG; + +#undef TYPE_NUMERIC +FIELDTYPE *TYPE_NUMERIC; + +/* ./fty_regex.c */ + +#include <regex.h> + +typedef struct +{ + regex_t *pRegExp; + unsigned long *refCount; +} RegExp_Arg; + +#undef TYPE_REGEXP +FIELDTYPE *TYPE_REGEXP; diff --git a/Source/CursesDialog/form/mf_common.h b/Source/CursesDialog/form/mf_common.h new file mode 100644 index 0000000..6b1e8fe --- /dev/null +++ b/Source/CursesDialog/form/mf_common.h @@ -0,0 +1,93 @@ +/**************************************************************************** + * Copyright (c) 1998,2000 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * + ****************************************************************************/ + +/* Common internal header for menu and form library */ + +#if HAVE_CONFIG_H +# include <ncurses_cfg.h> +#endif + +#include <stdlib.h> +#include <sys/types.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#if DECL_ERRNO +extern int errno; +#endif + +/* in case of debug version we ignore the suppression of assertions */ +#ifdef TRACE +# ifdef NDEBUG +# undef NDEBUG +# endif +#endif + +#include <nc_alloc.h> + +#if USE_RCS_IDS +#define MODULE_ID(id) static const char Ident[] = id; +#else +#define MODULE_ID(id) /*nothing*/ +#endif + + +/* Maximum regular 8-bit character code */ +#define MAX_REGULAR_CHARACTER (0xff) + +#define SET_ERROR(code) (errno=(code)) +#define GET_ERROR() (errno) +#define RETURN(code) return( SET_ERROR(code) ) + +/* The few common values in the status fields for menus and forms */ +#define _POSTED (0x01) /* menu or form is posted */ +#define _IN_DRIVER (0x02) /* menu or form is processing hook routine */ + +/* Call object hook */ +#define Call_Hook( object, handler ) \ + if ( (object) && ((object)->handler) )\ + {\ + (object)->status |= _IN_DRIVER;\ + (object)->handler(object);\ + (object)->status &= ~_IN_DRIVER;\ + } + +#define INLINE + +#ifndef TRACE +# if CC_HAS_INLINE_FUNCS +# undef INLINE +# define INLINE inline +# endif +#endif diff --git a/Source/CursesDialog/form/nc_alloc.h b/Source/CursesDialog/form/nc_alloc.h new file mode 100644 index 0000000..f49ea93 --- /dev/null +++ b/Source/CursesDialog/form/nc_alloc.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Thomas E. Dickey <dickey@clark.net> 1996,1997 * + ****************************************************************************/ +/* $Id$ */ + +#ifndef NC_ALLOC_included +#define NC_ALLOC_included 1 + +#if HAVE_LIBDMALLOC +#include <dmalloc.h> /* Gray Watson's library */ +#else +#undef HAVE_LIBDMALLOC +#define HAVE_LIBDMALLOC 0 +#endif + +#if HAVE_LIBDBMALLOC +#include <dbmalloc.h> /* Conor Cahill's library */ +#else +#undef HAVE_LIBDBMALLOC +#define HAVE_LIBDBMALLOC 0 +#endif + +#ifndef NO_LEAKS +#define NO_LEAKS 0 +#endif + +#if HAVE_LIBDBMALLOC || HAVE_LIBDMALLOC || NO_LEAKS +#define HAVE_NC_FREEALL 1 +struct termtype; +extern void _nc_free_and_exit(int) GCC_NORETURN; +extern void _nc_free_tparm(void); +extern void _nc_leaks_dump_entry(void); +#define ExitProgram(code) _nc_free_and_exit(code) +#endif + +#ifndef HAVE_NC_FREEALL +#define HAVE_NC_FREEALL 0 +#endif + +#ifndef ExitProgram +#define ExitProgram(code) return code +#endif + +/* doalloc.c */ +extern void *_nc_doalloc(void *, size_t); +#if !HAVE_STRDUP +/* #define strdup _nc_strdup */ +extern char *_nc_strdup(const char *); +#endif + +#define typeMalloc(type,elts) (type *)malloc((elts)*sizeof(type)) +#define typeCalloc(type,elts) (type *)calloc((elts),sizeof(type)) +#define typeRealloc(type,elts,ptr) (type *)_nc_doalloc(ptr, (elts)*sizeof(type)) + +#endif /* NC_ALLOC_included */ |