Tutorial 3: Read and write commands

This tutorial shows how to integrate read and write functions to the shell interface. The general mechanism works as follows. We first define a file type, and name it using a tag. Then we can enable read and write commands for this tag to a store type, which result in commands read_<tag> --<flag> and write_<tag> --<flag>, where <tag> is the tag name of the file type and <flag> is the flag name of the store type.

Our tutorial catches up where we left in the previous tutorial and defines a single store type for strings, and adds a function to print store elements.

#include <alice/alice.hpp>

#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

namespace alice
{

ALICE_ADD_STORE( std::string, "str", "s", "string", "strings" )

ALICE_PRINT_STORE( std::string, os, element )
{
  os << element << std::endl;
}

We now add the file type to read and write to text files using the macro ALICE_ADD_FILE_TYPE, which receives the tag name as first argument and a string defining it as second argument. The second argument will be used to generate help strings.

ALICE_ADD_FILE_TYPE( text, "Text" )

If we wish to only read from or only write to a file type, we can use the macros ALICE_ADD_FILE_TYPE_READ_ONLY or ALICE_ADD_FILE_TYPE_WRITE_ONLY, respectively. They have the same signature.

Once the file type is declared, we can link the string store type to the file type and add functions to read from files and to write from files. Reading from files is enabled using the macro ALICE_READ_FILE, which receives four parameters. The first two parameters are store type and tag name. The third parameter is the variable name containing the filename, and the last parameter gives access to the command parsing interface, which we won’t use in this tutorial.

ALICE_READ_FILE( std::string, text, filename, cmd )
{
  std::ifstream in( filename.c_str(), std::ifstream::in );
  std::stringstream buffer;
  buffer << in.rdbuf();
  return buffer.str();
}

Similarly, we enable writing from files using the macro ALICE_WRITE_FILE. It receives one further parameter called element, which is a variable accessing the current store element that should be written to a file.

ALICE_WRITE_FILE( std::string, text, element, filename, cmd )
{
  std::ofstream out( filename.c_str(), std::ofstream::out );
  out << element;
}

That’s all we need to read and write from files. Finally, we add one further command to manipulate store entries. The command upper will allow to change string elements into upper case.

ALICE_COMMAND(upper, "Manipulation", "changes string to upper bound")
{
  auto& str = store<std::string>().current();
  std::transform( str.begin(), str.end(), str.begin(), ::toupper );
}

}

ALICE_MAIN( tutorial3 )