diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | hscript/script.cc | 74 | ||||
-rw-r--r-- | hscript/script.hh | 29 | ||||
-rw-r--r-- | tests/scripts/0017-line-too-long.installfile | 5 | ||||
-rw-r--r-- | tools/hscript-validate/validator.cc | 39 | ||||
-rw-r--r-- | util/output.hh | 39 |
6 files changed, 157 insertions, 31 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ac98dfb..b854c6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,5 +10,7 @@ pkg_check_modules(LIBUDEV REQUIRED libudev) pkg_check_modules(PARTED REQUIRED libparted) find_library(BCNM_LIBRARY REQUIRED wpactrl PATH_SUFFIXES bcnm) +include_directories(.) + add_subdirectory(hscript) add_subdirectory(tools) diff --git a/hscript/script.cc b/hscript/script.cc index 748b09a..a9c39ab 100644 --- a/hscript/script.cc +++ b/hscript/script.cc @@ -18,6 +18,10 @@ #include "network.hh" #include "user.hh" +#include "util/output.hh" + +#define LINE_MAX 512 + namespace Horizon { struct Script::ScriptPrivate { @@ -34,35 +38,67 @@ struct Script::ScriptPrivate { }; Script::Script() { + internal = new ScriptPrivate; } const Script *Script::load(std::string path, ScriptOptions opts) { - std::ifstream file; - std::string maybe_error; - - file.exceptions(std::ios::badbit); - try { - file.open(path); - } catch(const std::ios::failure &error) { - maybe_error = error.what(); - } catch(const std::exception &error) { - maybe_error = error.what(); - } + std::ifstream file(path); if(!file) { - std::cerr << "Cannot open installfile at \"" << path << "\": "; - std::cerr << maybe_error; - std::cerr << std::endl; + output_error(path, "Cannot open installfile", "", + (opts.test(Pretty))); return nullptr; } return Script::load(file, opts); } -const Script *Script::load(std::istream &, ScriptOptions) { - Script *foo = new Script; - delete foo; - std::cout << "loaded" << std::endl; - return nullptr; +const Script *Script::load(std::istream &sstream, ScriptOptions opts) { + Script *the_script = new Script; + + int lineno = 0; + char nextline[LINE_MAX]; + const std::string delim(" \t"); + + while(sstream.getline(nextline, sizeof(nextline))) { + lineno++; + if(nextline[0] == '#') { + /* This is a comment line; ignore it. */ + continue; + } + + const std::string line(nextline); + std::string::size_type start, key_end; + start = line.find_first_not_of(delim); + if(start == std::string::npos) { + /* This is a blank line; ignore it. */ + continue; + } + + key_end = line.find_first_of(delim, start); + if(key_end == std::string::npos) { + /* Key without value */ + output_error("installfile:" + std::to_string(lineno), + "key '" + line.substr(start) + "' has no value", + "", (opts.test(Pretty))); + } + } + + if(sstream.fail() && !sstream.eof()) { + output_error("installfile:" + std::to_string(lineno + 1), + "line exceeds maximum length", + "Maximum length for line is " + std::to_string(LINE_MAX), + (opts.test(Pretty))); + delete the_script; + return nullptr; + } + + if(sstream.bad() && !sstream.eof()) { + output_error("installfile:" + std::to_string(lineno), + "I/O error reading installfile", "", + (opts.test(Pretty))); + } + + return the_script; } bool Script::validate() { diff --git a/hscript/script.hh b/hscript/script.hh index 1150e78..8c0f619 100644 --- a/hscript/script.hh +++ b/hscript/script.hh @@ -16,24 +16,29 @@ #include <string> #include <vector> #include <memory> +#include <bitset> namespace Horizon { /**** Script option flags ****/ -/*! Don't stop after the first error. */ -#define SCRIPT_KEEP_GOING 0x0001 -/*! Ensure network resources are available. */ -#define SCRIPT_USE_NETWORK 0x0002 -/*! Treat warnings as errors. */ -#define SCRIPT_STRICT_MODE 0x0004 -/*! This is an Installation Environment - validate more keys. */ -#define SCRIPT_INSTALL_ENV 0x0008 -/*! "Pretty" output - used in interactive tooling only. */ -#define SCRIPT_PRETTY 0x0010 +enum ScriptOptionFlags { + /*! Don't stop after the first error. */ + KeepGoing, + /*! Ensure network resources are available. */ + UseNetwork, + /*! Treat warnings as errors. */ + StrictMode, + /*! This is an Installation Environment - validate more keys. */ + InstallEnvironment, + /*! "Pretty" output - used in interactive tooling only. */ + Pretty, + /*! Count of flags */ + NumFlags +}; -typedef uint32_t ScriptOptions; +typedef std::bitset<ScriptOptionFlags::NumFlags> ScriptOptions; /*! Defines the Script class, which represents a HorizonScript. */ @@ -61,7 +66,7 @@ public: private: struct ScriptPrivate; /*! Internal data. */ - const std::unique_ptr<ScriptPrivate> internal; + ScriptPrivate *internal; }; } diff --git a/tests/scripts/0017-line-too-long.installfile b/tests/scripts/0017-line-too-long.installfile new file mode 100644 index 0000000..f208b5f --- /dev/null +++ b/tests/scripts/0017-line-too-long.installfile @@ -0,0 +1,5 @@ +network true +hostname test.machine +pkginstall abiword abuild-doc adelie-base adelie-keys adelie-wallpapers alegreya alsa-utils anonymous-pro apk-tools-static at at-doc audacious audacious-dbg audacious-dev audacious-plugins audacious-plugins-dbg bash-binsh bash-doc bc bind-tools binutils-doc bsdwhois bubblewrap-nosuid build-tools calligra cargo checkbashisms chelf chrony clearsans cmd:mkfs.vfat cmd:wish command-not-found console-keymaps console-setup-doc consolekit2 consolekit2-dbg cryptsetup cups dash debianutils-which dejagnu dhcpcd dosfstools dracut dracut-doc dracut-lvm e2fsprogs e2fsprogs-doc easy-kernel-power8 easy-kernel-power8-modules ebgaramond emacs-nox essays1743 eudev-dev evince fantasque-sans-mono fastjar ffmpeg ffmpeg-doc ffmpeg-libs fifth-leg fira fira-code firefox-esr flex free42 fuse-exfat gcc-doc gcompat gdb git-doc git-email gnumeric gnupg gptfdisk grub grub-ieee1275 gutenprint gwenview hdparm heirloom-devtools hermit heuristica-otf htop hunkyfonts hunspell imagemagick iproute2 iproute2-doc iputils iso-codes jpegoptim kate-dbg kbd kbd-keymaps kcachegrind kde-graphics kde-gtk-config kde-system kde-utilities kdeplasma-addons kgpg khelpcenter klickety kmix kolourpaint konsole kpat krdc krita ksysguard-lang ktorrent ktorrent-doc kwin kwrite lame libedit-dbg libertine-fonts libreoffice-calc libx11-dbg lighttpd links linux-firmware-amdgpu linux-firmware-radeon linux-headers linux-pam-doc lm_sensors lmms lsof lvm2-doc lxqt-desktop lynx lz4 mac-fdisk make-doc marble mednaffe mesa-dbg mesa-demos mesa-demos-dbg mesa-dri-swrast meson minicom mkfontscale-doc modemmanager monoid montecarlo mozjs mtr mtr-gtk musl-dbg nano ncurses-terminfo netcat netifrc netifrc-doc netsurf nmap nmap-ncat node nvi oclock okteta okular opal-utils openjdk8 openrc openrc-doc openssh openssh-doc openssl oprofile oprofile-doc optipng otf-source-code-pro otf-source-sans-pro oxygen-icons5 papirus-icons parted parted-dev partitionmanager pciutils perl-app-licensecheck perl-json phonon-vlc php7 php7-curl php7-dom php7-json php7-openssl php7-simplexml pidgin pidgin-otr pigz pinentry-gtk pkgconf plasma-desktop plasma-desktop-doc postgresql procps-doc pulseaudio pulseaudio-alsa pulseaudio-dev purple-plugin-pack py3-docutils py3-lxml py3-mako py3-packaging py3-tox qastools qemu-riscv64 qemu-system-riscv64 qemu-user qpdfview qt-creator qt5-qtbase-dbg qt5-qtbase-dev qt5-qtdeclarative-dev qt5-qtpositioning qt5-qttools qt5-qtwebchannel quassel-client quassel-dbg rdesktop rpm2targz rsync ruby ruby-dbg ruby-irb rust s6-linux-init screen sg3_utils shadow-doc socat spectacle sqlite squashfs-tools ssmtp stdman strace systemsettings tcpdump tcpdump-doc texinfo the_silver_searcher thunderbird tigervnc tmux traceroute tree trigger-rally trojita ttc-iosevka ttf-dejavu ttf-liberation ttf-noto tzdata umbrello umbrello-doc urw-base35-fonts usbutils user-manager util-linux-doc utmps utmps-libs valgrind vimdiff vlc-plugins-lua vlc-pulse vlc-qt weechat weechat-python x11 x11vnc x264 xclip xf86-input-evdev xf86-video-ati xf86-video-ati-doc xf86-video-fbdev xfsprogs xfsprogs-doc xfwm4 xmlto xmoto xorg-fonts xorg-server xorg-server-xephyr xorg-server-xnest xorriso xterm youtube-dl zsh-doc +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +mount /dev/sda1 / diff --git a/tools/hscript-validate/validator.cc b/tools/hscript-validate/validator.cc index e69de29..e9e1979 100644 --- a/tools/hscript-validate/validator.cc +++ b/tools/hscript-validate/validator.cc @@ -0,0 +1,39 @@ +/* + * validator.cc - Implementation of the HorizonScript validation utility + * Project Horizon + * + * Copyright (c) 2019 Adélie Linux and contributors. All rights reserved. + * This code is licensed under the AGPL 3.0 license, as noted in the + * LICENSE-code file in the root directory of this repository. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#include "hscript/script.hh" +#include "util/output.hh" + +int main(int argc, char *argv[]) { + const Horizon::Script *my_script; + Horizon::ScriptOptions opts; + + if(argc < 2) { + output_error("hscript-validate", "No installfile specified", "", true); + std::cerr << "Run `" << argv[0] << " --help` for usage information." << std::endl; + return EXIT_FAILURE; + } + + std::cout << "\033[1mHorizonScript Validation Utility version 0.1.0\033[0m" << std::endl; + std::cout << "Copyright (c) 2019 Adélie Linux and contributors. AGPL-3.0 license." << std::endl; + std::cout << std::endl; + + opts.set(Horizon::ScriptOptionFlags::Pretty); + + my_script = Horizon::Script::load(argv[1], opts); + if(my_script == nullptr) { + std::cout << "Could not load the specified script." << std::endl; + return EXIT_FAILURE; + } + delete my_script; + + return EXIT_SUCCESS; +} diff --git a/util/output.hh b/util/output.hh new file mode 100644 index 0000000..9281301 --- /dev/null +++ b/util/output.hh @@ -0,0 +1,39 @@ +/* + * output.hh - Miscellaneous output routines + * util, the utility library for + * Project Horizon + * + * Copyright (c) 2019 Adélie Linux and contributors. All rights reserved. + * This code is licensed under the AGPL 3.0 license, as noted in the + * LICENSE-code file in the root directory of this repository. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#ifndef __HORIZON_OUTPUT_HH_ +#define __HORIZON_OUTPUT_HH_ + +#include <string> +#include <iostream> + +/*! Prints an error message to the cerr stream. + * @param where The location where the error occurred. + * @param message The error that occurred. + * @param detail Additional detail for the error, if available. + * @param pretty Whether or not to colourise (interactive output). + */ +inline void output_error(std::string where, std::string message, + std::string detail = "", bool pretty = false) { + std::cerr << where << ": "; + if(pretty) std::cerr << "\033[31;1m"; + std::cerr << "error: "; + if(pretty) std::cerr << "\033[0;1m"; + std::cerr << message; + if(pretty) std::cerr << "\033[0m"; + if(!detail.empty()) { + std::cerr << ": " << detail; + } + std::cerr << std::endl; +} + +#endif /* !__HORIZON_OUTPUT_HH_ */ |