# HG changeset patch # User František Kučera # Date 1544376800 -3600 # Node ID aadef824dc9396decf47fc6f7c16e2646eaa4f4a # Parent 454cfb01cf955e415070146a748bad8f138bad23 cmake diff -r 454cfb01cf95 -r aadef824dc93 ArgumentsCommand.h --- a/ArgumentsCommand.h Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/** - * Relational pipes - * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include - -#include "Command.h" - -namespace relpipe { -namespace in { -namespace cli { - -class ArgumentsCommand : public Command { -public: - - void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector& arguments) override { - using namespace relpipe::writer; - - size_t i = 0; - string_t relationName = arguments[i++]; - integer_t attributeCount = std::stoul(arguments[i++]); // TODO: use integer data type's method? - boolean_t writeHeader = true; // TODO: add option for header omitting - - // TODO: check argument count - - std::shared_ptr writer(Factory::create(output)); - - std::vector attributes(attributeCount); - - for (size_t j = 0; j < attributeCount; j++) { - string_t attributeName = arguments[i++]; - TypeId attributeType = writer->toTypeId(arguments[i++]); - attributes[j] = {attributeName, attributeType}; - } - - writer->startRelation(relationName, attributes, writeHeader); - - for (; i < arguments.size(); i++) { - writer->writeAttribute(arguments[i]); - } - } -}; - -} -} -} diff -r 454cfb01cf95 -r aadef824dc93 CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CMakeLists.txt Sun Dec 09 18:33:20 2018 +0100 @@ -0,0 +1,19 @@ +# Relational pipes +# Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +project (relpipe-in-cli.cpp) +cmake_minimum_required(VERSION 2.8) +add_subdirectory (src) diff -r 454cfb01cf95 -r aadef824dc93 Command.h --- a/Command.h Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/** - * Relational pipes - * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include -#include -#include -#include -#include - - -namespace relpipe { -namespace in { -namespace cli { - -class Command { -public: - virtual ~Command() = default; - - /** - * Processes the inputs (stream + arguments) and generates output in the relational pipes format. - * - * @param input usually STDIN, may not be used if all data are passed as CLI arguments - * @param output usually STDOUT, relational data is passed here - * @param command command name, usualy not needed, may be significant if the same Command instance is used for several commands - * @param arguments CLI arguments containing data or parameters (format is specific to each command) - */ - virtual void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector &arguments) = 0; - -}; - -} -} -} diff -r 454cfb01cf95 -r aadef824dc93 DemoCommand.h --- a/DemoCommand.h Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/** - * Relational pipes - * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include -#include -#include -#include -#include - -#include - -#include "Command.h" - -namespace relpipe { -namespace in { -namespace cli { - -class DemoCommand : public Command { -public: - - void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector& arguments) override { - using namespace relpipe::writer; - std::shared_ptr writer(Factory::create(output)); - - - // Various data types passed as strings - writer->startRelation(L"table_from_strings",{ - {L"s", TypeId::STRING}, - {L"i", TypeId::INTEGER}, - {L"b", TypeId::BOOLEAN} - }, true); - - writer->writeAttribute(L"a"); - writer->writeAttribute(L"1"); - writer->writeAttribute(L"true"); - - writer->writeAttribute(L"b"); - writer->writeAttribute(L"2"); - writer->writeAttribute(L"false"); - - - // Various data types passed as raw pointers + typeids - writer->startRelation(L"from_raw_pointers",{ - {L"s", TypeId::STRING}, - {L"i", TypeId::INTEGER}, - {L"b", TypeId::BOOLEAN} - }, true); - - string_t sValue; - integer_t iValue; - boolean_t bValue; - - for (int i = 0; i < 8; i++) { - sValue.append(L"*"); - iValue = i + 1; - bValue = iValue % 2 == 0; - writer->writeAttribute(&sValue, typeid (sValue)); - writer->writeAttribute(&iValue, typeid (iValue)); - writer->writeAttribute(&bValue, typeid (bValue)); - } - } -}; - -} -} -} diff -r 454cfb01cf95 -r aadef824dc93 Makefile --- a/Makefile Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -# -# There exist several targets which are by default empty and which can be -# used for execution of your targets. These targets are usually executed -# before and after some main targets. They are: -# -# .build-pre: called before 'build' target -# .build-post: called after 'build' target -# .clean-pre: called before 'clean' target -# .clean-post: called after 'clean' target -# .clobber-pre: called before 'clobber' target -# .clobber-post: called after 'clobber' target -# .all-pre: called before 'all' target -# .all-post: called after 'all' target -# .help-pre: called before 'help' target -# .help-post: called after 'help' target -# -# Targets beginning with '.' are not intended to be called on their own. -# -# Main targets can be executed directly, and they are: -# -# build build a specific configuration -# clean remove built files from a configuration -# clobber remove all built files -# all build all configurations -# help print help mesage -# -# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and -# .help-impl are implemented in nbproject/makefile-impl.mk. -# -# Available make variables: -# -# CND_BASEDIR base directory for relative paths -# CND_DISTDIR default top distribution directory (build artifacts) -# CND_BUILDDIR default top build directory (object files, ...) -# CONF name of current configuration -# CND_PLATFORM_${CONF} platform name (current configuration) -# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) -# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) -# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) -# CND_PACKAGE_DIR_${CONF} directory of package (current configuration) -# CND_PACKAGE_NAME_${CONF} name of package (current configuration) -# CND_PACKAGE_PATH_${CONF} path to package (current configuration) -# -# NOCDDL - - -# Environment -MKDIR=mkdir -CP=cp -CCADMIN=CCadmin - - -# build -build: .build-post - -.build-pre: -# Add your pre 'build' code here... - -.build-post: .build-impl -# Add your post 'build' code here... - - -# clean -clean: .clean-post - -.clean-pre: -# Add your pre 'clean' code here... - -.clean-post: .clean-impl -# Add your post 'clean' code here... - - -# clobber -clobber: .clobber-post - -.clobber-pre: -# Add your pre 'clobber' code here... - -.clobber-post: .clobber-impl -# Add your post 'clobber' code here... - - -# all -all: .all-post - -.all-pre: -# Add your pre 'all' code here... - -.all-post: .all-impl -# Add your post 'all' code here... - - -# build tests -build-tests: .build-tests-post - -.build-tests-pre: -# Add your pre 'build-tests' code here... - -.build-tests-post: .build-tests-impl -# Add your post 'build-tests' code here... - - -# run tests -test: .test-post - -.test-pre: build-tests -# Add your pre 'test' code here... - -.test-post: .test-impl -# Add your post 'test' code here... - - -# help -help: .help-post - -.help-pre: -# Add your pre 'help' code here... - -.help-post: .help-impl -# Add your post 'help' code here... - - - -# include project implementation makefile -include nbproject/Makefile-impl.mk - -# include project make variables -include nbproject/Makefile-variables.mk diff -r 454cfb01cf95 -r aadef824dc93 StdInCommand.h --- a/StdInCommand.h Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/** - * Relational pipes - * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "Command.h" - -namespace relpipe { -namespace in { -namespace cli { - -/** - * TODO: consider code merge with ArgumentsCommand - */ -class StdInCommand : public Command { -private: - relpipe::writer::boolean_t readStdIn; - std::wstring_convert> convertor; // TODO: support also other encodings. - - /** - * Reads next value from arguments and (if no arguments left) from input - * @param input - * @param arguments - * @param i current index in the arguments vector - * @param required if true, exception is thrown when no data found - * @return - */ - relpipe::writer::string_t readNext(std::istream& input, const std::vector& arguments, size_t& i, relpipe::writer::boolean_t required) { - using namespace relpipe::writer; - using namespace relpipe::cli; - - if (i < arguments.size()) { - return arguments[i++]; - } else if (readStdIn) { - std::stringstream value; - - while (true) { - char ch; - input.get(ch); - if (ch == 0 || input.eof() || input.fail()) break; - else value << ch; - } - - if (required && value.str().empty()) throw RelpipeCLIException(L"Missing value on STDIN.", CLI::EXIT_CODE_BAD_SYNTAX); - - return convertor.from_bytes(value.str()); - } else { - if (required) throw RelpipeCLIException(L"Missing value on CLI.", CLI::EXIT_CODE_BAD_SYNTAX); - return L""; - } - } - - -public: - - StdInCommand(relpipe::writer::boolean_t readStdIn) : - readStdIn(readStdIn) { - } - - void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector& arguments) override { - using namespace relpipe::writer; - - size_t i = 0; - string_t relationName = readNext(input, arguments, i, true); - integer_t attributeCount = std::stoul(readNext(input, arguments, i, true)); // TODO: use integer data type's method? - boolean_t writeHeader = true; // TODO: add option for header omitting - - std::shared_ptr writer(Factory::create(output)); - - std::vector attributes(attributeCount); - - for (size_t j = 0; j < attributeCount; j++) { - string_t attributeName = readNext(input, arguments, i, true); - TypeId attributeType = writer->toTypeId(readNext(input, arguments, i, true)); - attributes[j] = {attributeName, attributeType}; - } - - writer->startRelation(relationName, attributes, writeHeader); - - while (true) { - string_t value = readNext(input, arguments, i, false); - if (value.empty() && (input.eof() || input.fail() || (!readStdIn && i >= arguments.size()))) break; - else writer->writeAttribute(value); - // TODO: check attribute count (avoid unfinished records) - } - } -}; - -} -} -} diff -r 454cfb01cf95 -r aadef824dc93 nbproject/Makefile-Debug.mk --- a/nbproject/Makefile-Debug.mk Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -# -# Generated Makefile - do not edit! -# -# Edit the Makefile in the project folder instead (../Makefile). Each target -# has a -pre and a -post target defined where you can add customized code. -# -# This makefile implements configuration specific macros and targets. - - -# Environment -MKDIR=mkdir -CP=cp -GREP=grep -NM=nm -CCADMIN=CCadmin -RANLIB=ranlib -CC=gcc -CCC=g++ -CXX=g++ -FC=gfortran -AS=as - -# Macros -CND_PLATFORM=GNU-Linux -CND_DLIB_EXT=so -CND_CONF=Debug -CND_DISTDIR=dist -CND_BUILDDIR=build - -# Include project Makefile -include Makefile - -# Object Directory -OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} - -# Object Files -OBJECTFILES= \ - ${OBJECTDIR}/relpipe-in-cli.o - - -# C Compiler Flags -CFLAGS= - -# CC Compiler Flags -CCFLAGS=-fsanitize=address -CXXFLAGS=-fsanitize=address - -# Fortran Compiler Flags -FFLAGS= - -# Assembler Flags -ASFLAGS= - -# Link Libraries and Options -LDLIBSOPTIONS=`pkg-config --libs relpipe-lib-writer.cpp` `pkg-config --libs relpipe-lib-cli.cpp` - -# Build Targets -.build-conf: ${BUILD_SUBPROJECTS} - "${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/relpipe-in-cli.cpp - -${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/relpipe-in-cli.cpp: ${OBJECTFILES} - ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} - ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/relpipe-in-cli.cpp ${OBJECTFILES} ${LDLIBSOPTIONS} - -${OBJECTDIR}/relpipe-in-cli.o: relpipe-in-cli.cpp - ${MKDIR} -p ${OBJECTDIR} - ${RM} "$@.d" - $(COMPILE.cc) -g `pkg-config --cflags relpipe-lib-writer.cpp` `pkg-config --cflags relpipe-lib-cli.cpp` -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/relpipe-in-cli.o relpipe-in-cli.cpp - -# Subprojects -.build-subprojects: - -# Clean Targets -.clean-conf: ${CLEAN_SUBPROJECTS} - ${RM} -r ${CND_BUILDDIR}/${CND_CONF} - -# Subprojects -.clean-subprojects: - -# Enable dependency checking -.dep.inc: .depcheck-impl - -include .dep.inc diff -r 454cfb01cf95 -r aadef824dc93 nbproject/Makefile-Release.mk --- a/nbproject/Makefile-Release.mk Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -# -# Generated Makefile - do not edit! -# -# Edit the Makefile in the project folder instead (../Makefile). Each target -# has a -pre and a -post target defined where you can add customized code. -# -# This makefile implements configuration specific macros and targets. - - -# Environment -MKDIR=mkdir -CP=cp -GREP=grep -NM=nm -CCADMIN=CCadmin -RANLIB=ranlib -CC=gcc -CCC=g++ -CXX=g++ -FC=gfortran -AS=as - -# Macros -CND_PLATFORM=GNU-Linux -CND_DLIB_EXT=so -CND_CONF=Release -CND_DISTDIR=dist -CND_BUILDDIR=build - -# Include project Makefile -include Makefile - -# Object Directory -OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} - -# Object Files -OBJECTFILES= \ - ${OBJECTDIR}/relpipe-in-cli.o - - -# C Compiler Flags -CFLAGS= - -# CC Compiler Flags -CCFLAGS= -CXXFLAGS= - -# Fortran Compiler Flags -FFLAGS= - -# Assembler Flags -ASFLAGS= - -# Link Libraries and Options -LDLIBSOPTIONS=`pkg-config --libs relpipe-lib-writer.cpp` `pkg-config --libs relpipe-lib-cli.cpp` - -# Build Targets -.build-conf: ${BUILD_SUBPROJECTS} - "${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/relpipe-in-cli.cpp - -${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/relpipe-in-cli.cpp: ${OBJECTFILES} - ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} - ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/relpipe-in-cli.cpp ${OBJECTFILES} ${LDLIBSOPTIONS} - -${OBJECTDIR}/relpipe-in-cli.o: relpipe-in-cli.cpp - ${MKDIR} -p ${OBJECTDIR} - ${RM} "$@.d" - $(COMPILE.cc) -O2 `pkg-config --cflags relpipe-lib-writer.cpp` `pkg-config --cflags relpipe-lib-cli.cpp` -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/relpipe-in-cli.o relpipe-in-cli.cpp - -# Subprojects -.build-subprojects: - -# Clean Targets -.clean-conf: ${CLEAN_SUBPROJECTS} - ${RM} -r ${CND_BUILDDIR}/${CND_CONF} - -# Subprojects -.clean-subprojects: - -# Enable dependency checking -.dep.inc: .depcheck-impl - -include .dep.inc diff -r 454cfb01cf95 -r aadef824dc93 nbproject/Makefile-impl.mk --- a/nbproject/Makefile-impl.mk Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -# -# Generated Makefile - do not edit! -# -# Edit the Makefile in the project folder instead (../Makefile). Each target -# has a pre- and a post- target defined where you can add customization code. -# -# This makefile implements macros and targets common to all configurations. -# -# NOCDDL - - -# Building and Cleaning subprojects are done by default, but can be controlled with the SUB -# macro. If SUB=no, subprojects will not be built or cleaned. The following macro -# statements set BUILD_SUB-CONF and CLEAN_SUB-CONF to .build-reqprojects-conf -# and .clean-reqprojects-conf unless SUB has the value 'no' -SUB_no=NO -SUBPROJECTS=${SUB_${SUB}} -BUILD_SUBPROJECTS_=.build-subprojects -BUILD_SUBPROJECTS_NO= -BUILD_SUBPROJECTS=${BUILD_SUBPROJECTS_${SUBPROJECTS}} -CLEAN_SUBPROJECTS_=.clean-subprojects -CLEAN_SUBPROJECTS_NO= -CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}} - - -# Project Name -PROJECTNAME=relpipe-in-cli.cpp - -# Active Configuration -DEFAULTCONF=Debug -CONF=${DEFAULTCONF} - -# All Configurations -ALLCONFS=Debug Release - - -# build -.build-impl: .build-pre .validate-impl .depcheck-impl - @#echo "=> Running $@... Configuration=$(CONF)" - "${MAKE}" -f nbproject/Makefile-${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .build-conf - - -# clean -.clean-impl: .clean-pre .validate-impl .depcheck-impl - @#echo "=> Running $@... Configuration=$(CONF)" - "${MAKE}" -f nbproject/Makefile-${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .clean-conf - - -# clobber -.clobber-impl: .clobber-pre .depcheck-impl - @#echo "=> Running $@..." - for CONF in ${ALLCONFS}; \ - do \ - "${MAKE}" -f nbproject/Makefile-$${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .clean-conf; \ - done - -# all -.all-impl: .all-pre .depcheck-impl - @#echo "=> Running $@..." - for CONF in ${ALLCONFS}; \ - do \ - "${MAKE}" -f nbproject/Makefile-$${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .build-conf; \ - done - -# build tests -.build-tests-impl: .build-impl .build-tests-pre - @#echo "=> Running $@... Configuration=$(CONF)" - "${MAKE}" -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-tests-conf - -# run tests -.test-impl: .build-tests-impl .test-pre - @#echo "=> Running $@... Configuration=$(CONF)" - "${MAKE}" -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .test-conf - -# dependency checking support -.depcheck-impl: - @echo "# This code depends on make tool being used" >.dep.inc - @if [ -n "${MAKE_VERSION}" ]; then \ - echo "DEPFILES=\$$(wildcard \$$(addsuffix .d, \$${OBJECTFILES} \$${TESTOBJECTFILES}))" >>.dep.inc; \ - echo "ifneq (\$${DEPFILES},)" >>.dep.inc; \ - echo "include \$${DEPFILES}" >>.dep.inc; \ - echo "endif" >>.dep.inc; \ - else \ - echo ".KEEP_STATE:" >>.dep.inc; \ - echo ".KEEP_STATE_FILE:.make.state.\$${CONF}" >>.dep.inc; \ - fi - -# configuration validation -.validate-impl: - @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ - then \ - echo ""; \ - echo "Error: can not find the makefile for configuration '${CONF}' in project ${PROJECTNAME}"; \ - echo "See 'make help' for details."; \ - echo "Current directory: " `pwd`; \ - echo ""; \ - fi - @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ - then \ - exit 1; \ - fi - - -# help -.help-impl: .help-pre - @echo "This makefile supports the following configurations:" - @echo " ${ALLCONFS}" - @echo "" - @echo "and the following targets:" - @echo " build (default target)" - @echo " clean" - @echo " clobber" - @echo " all" - @echo " help" - @echo "" - @echo "Makefile Usage:" - @echo " make [CONF=] [SUB=no] build" - @echo " make [CONF=] [SUB=no] clean" - @echo " make [SUB=no] clobber" - @echo " make [SUB=no] all" - @echo " make help" - @echo "" - @echo "Target 'build' will build a specific configuration and, unless 'SUB=no'," - @echo " also build subprojects." - @echo "Target 'clean' will clean a specific configuration and, unless 'SUB=no'," - @echo " also clean subprojects." - @echo "Target 'clobber' will remove all built files from all configurations and," - @echo " unless 'SUB=no', also from subprojects." - @echo "Target 'all' will will build all configurations and, unless 'SUB=no'," - @echo " also build subprojects." - @echo "Target 'help' prints this message." - @echo "" - diff -r 454cfb01cf95 -r aadef824dc93 nbproject/Makefile-variables.mk --- a/nbproject/Makefile-variables.mk Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -# -# Generated - do not edit! -# -# NOCDDL -# -CND_BASEDIR=`pwd` -CND_BUILDDIR=build -CND_DISTDIR=dist -# Debug configuration -CND_PLATFORM_Debug=GNU-Linux -CND_ARTIFACT_DIR_Debug=dist/Debug/GNU-Linux -CND_ARTIFACT_NAME_Debug=relpipe-in-cli.cpp -CND_ARTIFACT_PATH_Debug=dist/Debug/GNU-Linux/relpipe-in-cli.cpp -CND_PACKAGE_DIR_Debug=dist/Debug/GNU-Linux/package -CND_PACKAGE_NAME_Debug=relpipe-in-cli.cpp.tar -CND_PACKAGE_PATH_Debug=dist/Debug/GNU-Linux/package/relpipe-in-cli.cpp.tar -# Release configuration -CND_PLATFORM_Release=GNU-Linux -CND_ARTIFACT_DIR_Release=dist/Release/GNU-Linux -CND_ARTIFACT_NAME_Release=relpipe-in-cli.cpp -CND_ARTIFACT_PATH_Release=dist/Release/GNU-Linux/relpipe-in-cli.cpp -CND_PACKAGE_DIR_Release=dist/Release/GNU-Linux/package -CND_PACKAGE_NAME_Release=relpipe-in-cli.cpp.tar -CND_PACKAGE_PATH_Release=dist/Release/GNU-Linux/package/relpipe-in-cli.cpp.tar -# -# include compiler specific variables -# -# dmake command -ROOT:sh = test -f nbproject/private/Makefile-variables.mk || \ - (mkdir -p nbproject/private && touch nbproject/private/Makefile-variables.mk) -# -# gmake command -.PHONY: $(shell test -f nbproject/private/Makefile-variables.mk || (mkdir -p nbproject/private && touch nbproject/private/Makefile-variables.mk)) -# -include nbproject/private/Makefile-variables.mk diff -r 454cfb01cf95 -r aadef824dc93 nbproject/Package-Debug.bash --- a/nbproject/Package-Debug.bash Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -#!/bin/bash -x - -# -# Generated - do not edit! -# - -# Macros -TOP=`pwd` -CND_PLATFORM=GNU-Linux -CND_CONF=Debug -CND_DISTDIR=dist -CND_BUILDDIR=build -CND_DLIB_EXT=so -NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging -TMPDIRNAME=tmp-packaging -OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/relpipe-in-cli.cpp -OUTPUT_BASENAME=relpipe-in-cli.cpp -PACKAGE_TOP_DIR=relpipe-in-cli.cpp/ - -# Functions -function checkReturnCode -{ - rc=$? - if [ $rc != 0 ] - then - exit $rc - fi -} -function makeDirectory -# $1 directory path -# $2 permission (optional) -{ - mkdir -p "$1" - checkReturnCode - if [ "$2" != "" ] - then - chmod $2 "$1" - checkReturnCode - fi -} -function copyFileToTmpDir -# $1 from-file path -# $2 to-file path -# $3 permission -{ - cp "$1" "$2" - checkReturnCode - if [ "$3" != "" ] - then - chmod $3 "$2" - checkReturnCode - fi -} - -# Setup -cd "${TOP}" -mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package -rm -rf ${NBTMPDIR} -mkdir -p ${NBTMPDIR} - -# Copy files and create directories and links -cd "${TOP}" -makeDirectory "${NBTMPDIR}/relpipe-in-cli.cpp/bin" -copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 - - -# Generate tar file -cd "${TOP}" -rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/relpipe-in-cli.cpp.tar -cd ${NBTMPDIR} -tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/relpipe-in-cli.cpp.tar * -checkReturnCode - -# Cleanup -cd "${TOP}" -rm -rf ${NBTMPDIR} diff -r 454cfb01cf95 -r aadef824dc93 nbproject/Package-Release.bash --- a/nbproject/Package-Release.bash Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -#!/bin/bash -x - -# -# Generated - do not edit! -# - -# Macros -TOP=`pwd` -CND_PLATFORM=GNU-Linux -CND_CONF=Release -CND_DISTDIR=dist -CND_BUILDDIR=build -CND_DLIB_EXT=so -NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging -TMPDIRNAME=tmp-packaging -OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/relpipe-in-cli.cpp -OUTPUT_BASENAME=relpipe-in-cli.cpp -PACKAGE_TOP_DIR=relpipe-in-cli.cpp/ - -# Functions -function checkReturnCode -{ - rc=$? - if [ $rc != 0 ] - then - exit $rc - fi -} -function makeDirectory -# $1 directory path -# $2 permission (optional) -{ - mkdir -p "$1" - checkReturnCode - if [ "$2" != "" ] - then - chmod $2 "$1" - checkReturnCode - fi -} -function copyFileToTmpDir -# $1 from-file path -# $2 to-file path -# $3 permission -{ - cp "$1" "$2" - checkReturnCode - if [ "$3" != "" ] - then - chmod $3 "$2" - checkReturnCode - fi -} - -# Setup -cd "${TOP}" -mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package -rm -rf ${NBTMPDIR} -mkdir -p ${NBTMPDIR} - -# Copy files and create directories and links -cd "${TOP}" -makeDirectory "${NBTMPDIR}/relpipe-in-cli.cpp/bin" -copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 - - -# Generate tar file -cd "${TOP}" -rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/relpipe-in-cli.cpp.tar -cd ${NBTMPDIR} -tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/relpipe-in-cli.cpp.tar * -checkReturnCode - -# Cleanup -cd "${TOP}" -rm -rf ${NBTMPDIR} diff -r 454cfb01cf95 -r aadef824dc93 nbproject/configurations.xml --- a/nbproject/configurations.xml Mon Dec 03 16:11:40 2018 +0100 +++ b/nbproject/configurations.xml Sun Dec 09 18:33:20 2018 +0100 @@ -1,109 +1,134 @@ + - - ArgumentsCommand.h - Command.h - DemoCommand.h - StdInCommand.h - - - - - relpipe-in-cli.cpp - - - + + + relpipe-in-cli.cpp + + - Makefile + CMakeLists.txt + build/Debug/Makefile + build/Release/Makefile - Makefile + ^(nbproject|build)$ + + . + + build/Debug/Makefile - + default - true + false false - - - - ../../src/relpipe-lib-writer.cpp/DataTypeWriter.h - ../../src/relpipe-lib-writer.cpp/DataTypeWriterBase.h - - - - 11 - -fsanitize=address + + + + + + + + build/Debug + ${MAKE} -f Makefile + ${MAKE} -f Makefile clean + build/Debug/src/relpipe-in-cli + + + ../relpipe-lib-writer.cpp/include/relpipe/writer + ../relpipe-lib-cli.cpp/include/relpipe/cli + src + ../relpipe-lib-writer.cpp/include + ../relpipe-lib-cli.cpp/include + build/Debug/src + + + + + build/Debug + ${CMAKE} -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${IDE_CC} -DCMAKE_CXX_COMPILER=${IDE_CXX} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../.. + true + + + + - - - `pkg-config --libs relpipe-lib-writer.cpp` - `pkg-config --libs relpipe-lib-cli.cpp` - - - - - - - - - - - - - + default - true + false false - - - 5 - - - 5 - 11 - - - 5 - - - 5 - - - - `pkg-config --libs relpipe-lib-writer.cpp` - `pkg-config --libs relpipe-lib-cli.cpp` - - - - - - - - - - - - - + + + + + build/Release + ${MAKE} -f Makefile + ${MAKE} -f Makefile clean + build/Release/src/welcome + + + src + + + NDEBUG + + + + + build/Release + ${CMAKE} -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=${IDE_CC} -DCMAKE_CXX_COMPILER=${IDE_CXX} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../.. + true + + diff -r 454cfb01cf95 -r aadef824dc93 nbproject/project.xml --- a/nbproject/project.xml Mon Dec 03 16:11:40 2018 +0100 +++ b/nbproject/project.xml Sun Dec 09 18:33:20 2018 +0100 @@ -9,15 +9,17 @@ h UTF-8 - + + . + Debug - 1 + 0 Release - 1 + 0 diff -r 454cfb01cf95 -r aadef824dc93 relpipe-in-cli.cpp --- a/relpipe-in-cli.cpp Mon Dec 03 16:11:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/** - * Relational pipes - * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "Command.h" -#include "ArgumentsCommand.h" -#include "DemoCommand.h" -#include "StdInCommand.h" - -using namespace relpipe::cli; -using namespace relpipe::in::cli; -using namespace relpipe::writer; - -Command* findCommand(string_t commandName) { - // TODO: better command names - // TODO: help command - if (commandName == L"demo") return new DemoCommand(); - else if (commandName == L"generate") return new ArgumentsCommand(); - else if (commandName == L"generate-without-stdin") return new StdInCommand(false); // TODO: just for testing, StdInCommand(false) should work same as ArgumentsCommand() - else if (commandName == L"generate-from-stdin") return new StdInCommand(true); - else throw RelpipeCLIException(L"Unknown command: " + commandName, CLI::EXIT_CODE_UNKNOWN_COMMAND); -} - -int main(int argc, char** argv) { - setlocale(LC_ALL, ""); - CLI::untieStdIO(); - CLI cli(argc, argv); - - int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR; - - try { - if (cli.arguments().size() > 0) { - - const wstring commandName = cli.arguments()[0]; - vector arguments(cli.arguments().size() - 1); - for (int i = 1; i < cli.arguments().size(); i++) { - arguments[i - 1] = cli.arguments()[i]; - } - - std::shared_ptr command(findCommand(commandName)); - command->process(cin, cout, commandName, arguments); - resultCode = CLI::EXIT_CODE_SUCCESS; - - } else { - throw RelpipeCLIException(L"Missing command…", CLI::EXIT_CODE_BAD_SYNTAX); - } - } catch (RelpipeCLIException e) { - fwprintf(stderr, L"Caught CLI exception: %ls\n", e.getMessge().c_str()); - fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount()); - resultCode = e.getExitCode(); - } catch (RelpipeWriterException e) { - fwprintf(stderr, L"Caught Writer exception: %ls\n", e.getMessge().c_str()); - fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount()); - resultCode = CLI::EXIT_CODE_DATA_ERROR; - } - - return resultCode; -} diff -r 454cfb01cf95 -r aadef824dc93 src/ArgumentsCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ArgumentsCommand.h Sun Dec 09 18:33:20 2018 +0100 @@ -0,0 +1,68 @@ +/** + * Relational pipes + * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +#include "Command.h" + +namespace relpipe { +namespace in { +namespace cli { + +class ArgumentsCommand : public Command { +public: + + void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector& arguments) override { + using namespace relpipe::writer; + + size_t i = 0; + string_t relationName = arguments[i++]; + integer_t attributeCount = std::stoul(arguments[i++]); // TODO: use integer data type's method? + boolean_t writeHeader = true; // TODO: add option for header omitting + + // TODO: check argument count + + std::shared_ptr writer(Factory::create(output)); + + std::vector attributes(attributeCount); + + for (size_t j = 0; j < attributeCount; j++) { + string_t attributeName = arguments[i++]; + TypeId attributeType = writer->toTypeId(arguments[i++]); + attributes[j] = {attributeName, attributeType}; + } + + writer->startRelation(relationName, attributes, writeHeader); + + for (; i < arguments.size(); i++) { + writer->writeAttribute(arguments[i]); + } + } +}; + +} +} +} diff -r 454cfb01cf95 -r aadef824dc93 src/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/CMakeLists.txt Sun Dec 09 18:33:20 2018 +0100 @@ -0,0 +1,37 @@ +# Relational pipes +# Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(EXECUTABLE_FILE "relpipe-in-cli") + +# Relpipe libraries: +INCLUDE(FindPkgConfig) +pkg_check_modules (RELPIPE_LIBS relpipe-lib-writer.cpp relpipe-lib-cli.cpp) +include_directories(${RELPIPE_LIBS_INCLUDE_DIRS}) +link_directories(${RELPIPE_LIBS_LIBRARY_DIRS}) + +# Add ASan AddressSanitizer +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") +set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") +# From ASan wiki: "To get nicer stack traces in error messages add -fno-omit-frame-pointer." + +# Executable output: +add_executable( + ${EXECUTABLE_FILE} + relpipe-in-cli.cpp +) + +# Link libraries: +target_link_libraries(${EXECUTABLE_FILE} ${RELPIPE_LIBS_LIBRARIES}) diff -r 454cfb01cf95 -r aadef824dc93 src/Command.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Command.h Sun Dec 09 18:33:20 2018 +0100 @@ -0,0 +1,49 @@ +/** + * Relational pipes + * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include + + +namespace relpipe { +namespace in { +namespace cli { + +class Command { +public: + virtual ~Command() = default; + + /** + * Processes the inputs (stream + arguments) and generates output in the relational pipes format. + * + * @param input usually STDIN, may not be used if all data are passed as CLI arguments + * @param output usually STDOUT, relational data is passed here + * @param command command name, usualy not needed, may be significant if the same Command instance is used for several commands + * @param arguments CLI arguments containing data or parameters (format is specific to each command) + */ + virtual void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector &arguments) = 0; + +}; + +} +} +} diff -r 454cfb01cf95 -r aadef824dc93 src/DemoCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DemoCommand.h Sun Dec 09 18:33:20 2018 +0100 @@ -0,0 +1,82 @@ +/** + * Relational pipes + * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include "Command.h" + +namespace relpipe { +namespace in { +namespace cli { + +class DemoCommand : public Command { +public: + + void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector& arguments) override { + using namespace relpipe::writer; + std::shared_ptr writer(Factory::create(output)); + + + // Various data types passed as strings + writer->startRelation(L"table_from_strings",{ + {L"s", TypeId::STRING}, + {L"i", TypeId::INTEGER}, + {L"b", TypeId::BOOLEAN} + }, true); + + writer->writeAttribute(L"a"); + writer->writeAttribute(L"1"); + writer->writeAttribute(L"true"); + + writer->writeAttribute(L"b"); + writer->writeAttribute(L"2"); + writer->writeAttribute(L"false"); + + + // Various data types passed as raw pointers + typeids + writer->startRelation(L"from_raw_pointers",{ + {L"s", TypeId::STRING}, + {L"i", TypeId::INTEGER}, + {L"b", TypeId::BOOLEAN} + }, true); + + string_t sValue; + integer_t iValue; + boolean_t bValue; + + for (int i = 0; i < 8; i++) { + sValue.append(L"*"); + iValue = i + 1; + bValue = iValue % 2 == 0; + writer->writeAttribute(&sValue, typeid (sValue)); + writer->writeAttribute(&iValue, typeid (iValue)); + writer->writeAttribute(&bValue, typeid (bValue)); + } + } +}; + +} +} +} diff -r 454cfb01cf95 -r aadef824dc93 src/StdInCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/StdInCommand.h Sun Dec 09 18:33:20 2018 +0100 @@ -0,0 +1,118 @@ +/** + * Relational pipes + * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Command.h" + +namespace relpipe { +namespace in { +namespace cli { + +/** + * TODO: consider code merge with ArgumentsCommand + */ +class StdInCommand : public Command { +private: + relpipe::writer::boolean_t readStdIn; + std::wstring_convert> convertor; // TODO: support also other encodings. + + /** + * Reads next value from arguments and (if no arguments left) from input + * @param input + * @param arguments + * @param i current index in the arguments vector + * @param required if true, exception is thrown when no data found + * @return + */ + relpipe::writer::string_t readNext(std::istream& input, const std::vector& arguments, size_t& i, relpipe::writer::boolean_t required) { + using namespace relpipe::writer; + using namespace relpipe::cli; + + if (i < arguments.size()) { + return arguments[i++]; + } else if (readStdIn) { + std::stringstream value; + + while (true) { + char ch; + input.get(ch); + if (ch == 0 || input.eof() || input.fail()) break; + else value << ch; + } + + if (required && value.str().empty()) throw RelpipeCLIException(L"Missing value on STDIN.", CLI::EXIT_CODE_BAD_SYNTAX); + + return convertor.from_bytes(value.str()); + } else { + if (required) throw RelpipeCLIException(L"Missing value on CLI.", CLI::EXIT_CODE_BAD_SYNTAX); + return L""; + } + } + + +public: + + StdInCommand(relpipe::writer::boolean_t readStdIn) : + readStdIn(readStdIn) { + } + + void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector& arguments) override { + using namespace relpipe::writer; + + size_t i = 0; + string_t relationName = readNext(input, arguments, i, true); + integer_t attributeCount = std::stoul(readNext(input, arguments, i, true)); // TODO: use integer data type's method? + boolean_t writeHeader = true; // TODO: add option for header omitting + + std::shared_ptr writer(Factory::create(output)); + + std::vector attributes(attributeCount); + + for (size_t j = 0; j < attributeCount; j++) { + string_t attributeName = readNext(input, arguments, i, true); + TypeId attributeType = writer->toTypeId(readNext(input, arguments, i, true)); + attributes[j] = {attributeName, attributeType}; + } + + writer->startRelation(relationName, attributes, writeHeader); + + while (true) { + string_t value = readNext(input, arguments, i, false); + if (value.empty() && (input.eof() || input.fail() || (!readStdIn && i >= arguments.size()))) break; + else writer->writeAttribute(value); + // TODO: check attribute count (avoid unfinished records) + } + } +}; + +} +} +} diff -r 454cfb01cf95 -r aadef824dc93 src/relpipe-in-cli.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/relpipe-in-cli.cpp Sun Dec 09 18:33:20 2018 +0100 @@ -0,0 +1,82 @@ +/** + * Relational pipes + * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "Command.h" +#include "ArgumentsCommand.h" +#include "DemoCommand.h" +#include "StdInCommand.h" + +using namespace relpipe::cli; +using namespace relpipe::in::cli; +using namespace relpipe::writer; + +Command* findCommand(string_t commandName) { + // TODO: better command names + // TODO: help command + if (commandName == L"demo") return new DemoCommand(); + else if (commandName == L"generate") return new ArgumentsCommand(); + else if (commandName == L"generate-without-stdin") return new StdInCommand(false); // TODO: just for testing, StdInCommand(false) should work same as ArgumentsCommand() + else if (commandName == L"generate-from-stdin") return new StdInCommand(true); + else throw RelpipeCLIException(L"Unknown command: " + commandName, CLI::EXIT_CODE_UNKNOWN_COMMAND); +} + +int main(int argc, char** argv) { + setlocale(LC_ALL, ""); + CLI::untieStdIO(); + CLI cli(argc, argv); + + int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR; + + try { + if (cli.arguments().size() > 0) { + + const wstring commandName = cli.arguments()[0]; + vector arguments(cli.arguments().size() - 1); + for (int i = 1; i < cli.arguments().size(); i++) { + arguments[i - 1] = cli.arguments()[i]; + } + + std::shared_ptr command(findCommand(commandName)); + command->process(cin, cout, commandName, arguments); + resultCode = CLI::EXIT_CODE_SUCCESS; + + } else { + throw RelpipeCLIException(L"Missing command…", CLI::EXIT_CODE_BAD_SYNTAX); + } + } catch (RelpipeCLIException e) { + fwprintf(stderr, L"Caught CLI exception: %ls\n", e.getMessge().c_str()); + fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount()); + resultCode = e.getExitCode(); + } catch (RelpipeWriterException e) { + fwprintf(stderr, L"Caught Writer exception: %ls\n", e.getMessge().c_str()); + fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount()); + resultCode = CLI::EXIT_CODE_DATA_ERROR; + } + + return resultCode; +}