draft version
so one can do:
relpipe-in-fstab | relpipe-out-recfile | recsel -e 'type="btrfs"' | rec2csv | relpipe-in-csv | relpipe-out-asn1 | dumpasn1 -
--- a/src/RecfileHandler.h Sat Mar 30 01:12:42 2019 +0100
+++ b/src/RecfileHandler.h Sat Mar 30 15:50:29 2019 +0100
@@ -28,107 +28,98 @@
#include <relpipe/reader/typedefs.h>
#include <relpipe/reader/TypeId.h>
-#include <relpipe/reader/handlers/RelationalReaderValueHandler.h>
+#include <relpipe/reader/RelpipeReaderException.h>
+#include <relpipe/reader/handlers/RelationalReaderStringHandler.h>
#include <relpipe/reader/handlers/AttributeMetadata.h>
-#include "RecfileWriter.h"
-
namespace relpipe {
namespace out {
namespace recfile {
using namespace relpipe::reader;
-class RecfileHandler : public handlers::RelationalReaderValueHadler {
+class RecfileHandler : public handlers::RelationalReaderStringHadler {
private:
- shared_ptr<RecfileWriter> recfileWriter;
- std::vector<TypeId> columnTypes;
- std::vector<string_t> columnTypeCodes;
- std::vector<string_t> columnNames;
+ std::ostream& output;
+ wstring_convert<codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8
+ std::vector<TypeId> attributeTypes;
+ std::vector<string_t> attributeTypeCodes;
+ std::vector<string_t> attributeNames;
integer_t valueCount = 0;
- integer_t columnCount = 0;
+ integer_t attributeCount = 0;
integer_t relationCount = 0;
+ void writeRelationName(const string_t& name) {
+ // FIXME: escaping/filtering
+ output << "%rec: " << convertor.to_bytes(name) << std::endl;
+ }
+
+ const std::string toRecfileType(const TypeId& type) {
+ switch (type) {
+ case TypeId::BOOLEAN: return "bool";
+ case TypeId::INTEGER: return "int";
+ case TypeId::STRING: return ""; // TODO: string type?
+ default: throw RelpipeReaderException(L"Unsupported type – unable to convert to a Recfile type");
+ }
+ }
+
+ void writeAttributeMetadata(const handlers::AttributeMetadata& attribute) {
+ // FIXME: escaping/filtering
+ // FIXME: translate to recfile types
+ output << "%type: " << convertor.to_bytes(attribute.getAttributeName()) << " " << toRecfileType(attribute.getTypeId()) << std::endl;
+ }
+
+ void writeSeparator() {
+ output << std::endl;
+ }
+
+ void writeAttribute(const string_t& name, const TypeId& type, const string_t& value) {
+ // FIXME: escaping/filtering
+ output << convertor.to_bytes(name) << ": ";
+
+ for (char ch : convertor.to_bytes(value)) {
+ output << ch;
+ if (ch == '\n') output << "+ ";
+ }
+
+ output << std::endl;
+ }
+
public:
- RecfileHandler(std::ostream& output) : recfileWriter(new RecfileWriter(output)) {
+ RecfileHandler(std::ostream& output) : output(output) {
}
void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override {
valueCount = 0;
- columnCount = 0;
+ attributeCount = 0;
- if (relationCount == 0) {
- recfileWriter->writeStartSequence(); // root
- } else {
- recfileWriter->writeEndSequence();
- recfileWriter->writeEndSequence();
- }
+ if (relationCount) writeSeparator();
+
relationCount++;
- recfileWriter->writeStartSequence(); // relation
-
- recfileWriter->writeString(name);
-
+ writeRelationName(name);
- recfileWriter->writeStartSequence(); // relation metadata
- columnCount = attributes.size();
- columnTypes.resize(columnCount);
- columnTypeCodes.resize(columnCount);
- columnNames.resize(columnCount);
+ attributeCount = attributes.size();
+ attributeTypes.resize(attributeCount);
+ attributeTypeCodes.resize(attributeCount);
+ attributeNames.resize(attributeCount);
for (int i = 0; i < attributes.size(); i++) {
- columnNames[i] = attributes[i].getAttributeName();
- columnTypes[i] = attributes[i].getTypeId();
- columnTypeCodes[i] = attributes[i].getTypeName();
-
- recfileWriter->writeStartSequence(); // attribute-metadata
- recfileWriter->writeString(columnNames[i]);
- recfileWriter->writeString(columnTypeCodes[i]);
- recfileWriter->writeEndSequence();
+ attributeNames[i] = attributes[i].getAttributeName();
+ attributeTypes[i] = attributes[i].getTypeId();
+ attributeTypeCodes[i] = attributes[i].getTypeName();
+ writeAttributeMetadata(attributes[i]);
}
- recfileWriter->writeEndSequence();
-
}
- void attribute(const void* value, const std::type_info& type) override {
- integer_t i = valueCount % columnCount;
-
- if (i == 0 && valueCount) recfileWriter->writeEndSequence();
- if (i == 0) recfileWriter->writeStartSequence();
-
+ void attribute(const string_t& value) override {
+ integer_t i = valueCount % attributeCount;
+ if (i == 0) writeSeparator();
valueCount++;
-
- switch (columnTypes[i]) {
- case TypeId::BOOLEAN:
- {
- assert(type == typeid (boolean_t));
- auto* typedValue = static_cast<const boolean_t*> (value);
- recfileWriter->writeBoolean(*typedValue);
- break;
- }
- case TypeId::INTEGER:
- {
- assert(type == typeid (integer_t));
- auto* typedValue = static_cast<const integer_t*> (value);
- recfileWriter->writeInteger(*typedValue);
- break;
- }
- case TypeId::STRING:
- {
- assert(type == typeid (string_t));
- auto* typedValue = static_cast<const string_t*> (value);
- recfileWriter->writeString(*typedValue);
- break;
- }
- default:
- throw cli::RelpipeCLIException(L"Unsupported type in RecfileHandler.attribute()", cli::CLI::EXIT_CODE_UNEXPECTED_ERROR);
- }
-
+ writeAttribute(attributeNames[i], attributeTypes[i], value);
}
void endOfPipe() {
- if (valueCount) recfileWriter->writeEndSequence();
- if (relationCount) recfileWriter->writeEndSequence();
- recfileWriter->writeEndSequence();
+ if (valueCount) writeSeparator();
}
};
--- a/src/RecfileWriter.h Sat Mar 30 01:12:42 2019 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +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 <http://www.gnu.org/licenses/>.
- */
-#pragma once
-
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <vector>
-#include <codecvt>
-#include <locale>
-
-#include <relpipe/reader/typedefs.h>
-#include <relpipe/cli/RelpipeCLIException.h>
-
-using namespace std;
-
-namespace relpipe {
-namespace out {
-namespace recfile {
-
-using namespace relpipe::reader;
-
-/**
- * A simple library for writing ASN.1 BER encoded files.
- */
-class RecfileWriter {
-private:
- ostream& output;
- wstring_convert<codecvt_utf8<wchar_t>> convertor; // only UTF8String is supported
- int sequenceLevel = 0;
-
- void xxx_indent() {
- // FIXME: remove
- for (int i = 0; i < sequenceLevel; i++) output << " ";
- }
-
-public:
-
- RecfileWriter(std::ostream& output) : output(output) {
- }
-
- virtual ~RecfileWriter() {
- if (sequenceLevel) output << "Unable to close RecfileWriter because there are not ended sequences." << endl; // FIXME: better error handling
- output.flush();
- }
-
- void writeStartSequence() {
- xxx_indent();
- output << "sequence start" << endl;
-
- sequenceLevel++;
- }
-
- void writeEndSequence() {
- if (sequenceLevel == 0) throw cli::RelpipeCLIException(L"Unable to writeEndSequence() if not sequence is currently started.", cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // should not happen, error in the program
-
- sequenceLevel--;
-
- xxx_indent();
- output << "sequence end" << endl;
- }
-
- void writeBoolean(const boolean_t& value) {
- xxx_indent();
- output << "boolean" << (value ? "true" : "false") << endl;
- }
-
- void writeInteger(const integer_t& value) {
- xxx_indent();
- output << "integer: " << value << endl;
- }
-
- void writeString(const string_t& value) {
- xxx_indent();
- output << "string: " << convertor.to_bytes(value) << endl;
- }
-
-};
-
-}
-}
-}
\ No newline at end of file