0

I'm writing a program which takes a size, a redundancy, and some plaintext, and outputs a code of the plaintext. I'd like the size and redundancy used for encoding to be computed as follows:

  • If neither size nor redundancy is specified, the redundancy is 3/7 and the size is as big as it needs to be.
  • If the size is specified but the redundancy is not, the size is what's specified and the redundancy is whatever results from fitting the plaintext in the specified size. If the plaintext is less than 1/3 of what fits in that size, it's an error, because the maximum redundancy is 2/3 (2/3 and 3/7 come from Hamming codes). If the plaintext is too big, that too is an error.
  • If the redundancy is specified but the size is not, the size is as big as it needs to be.
  • If both are specified, the result is undefined. It could go with whichever is specified last or pick one arbitrarily.

The code is at https://github.com/phma/propolis; here is the relevant part:

#include <boost/program_options.hpp>
#include <cstdio>
#include <fstream>
#include <iostream>

using namespace std;
namespace po=boost::program_options;

int lastSizeRed=0;

void onSize(int size)
{
  lastSizeRed='s';
}

void onRed(string red)
{
  lastSizeRed='r';
}

int main(int argc,char **argv)
{
  int testflag=0,option_index=0,makedata=0;
  bool geneletters=false;
  int c,quality;
  double redundancy=0;
  int size=0;
  string text,infilename,outfilename;
  stringbuf filebuf;
  string redundancyStr,formatStr,patternStr;
  fstream infile;
  int format=FMT_PS,pattern=0;
  bool validCmd=true,helpFlag=false;
  po::options_description generic("Options");
  po::options_description hidden("Hidden options");
  po::options_description cmdline_options;
  po::positional_options_description p;
  po::variables_map vm;
  generic.add_options()
    ("size,s",po::value<int>(&size)->notifier(onSize),"Symbol size")
    ("redundancy,r",po::value<string>(&redundancyStr)->default_value("3/7")->notifier(onRed),"Redundancy (0,2/3]")
    ("text,t",po::value<string>(&text),"Text to encode")
    ("input,i",po::value<string>(&infilename),"File containing text to encode")
    ("output,o",po::value<string>(&outfilename),"Output file")
    ("format,f",po::value<string>(&formatStr)->default_value("ps"),"Output format")
    ("quality",po::value<int>(&quality)->default_value(1),"Quality of raster image (0-10)")
    ("pattern",po::value<string>(&patternStr),"Write a test pattern")
    ("writetables","Write decoding tables")
    ("geneletters","Optimize letters with genetic algorithm")
    ("test","Run tests")
    ("help","Show options");
  initialize();
  cmdline_options.add(generic).add(hidden);
  debugletters=0;
  try
  {
    po::store(po::command_line_parser(argc,argv).options(cmdline_options).positional(p).run(),vm);
    po::notify(vm);
    if (vm.count("test"))
      testflag=1;
    if (vm.count("writetables"))
      makedata=1;
    if (vm.count("geneletters"))
      geneletters=true;
    if (vm.count("help"))
      cout<<"Usage: propolis [options]\n"<<generic;
    cout<<"count(size)="<<vm.count("size")<<" count(redundancy)="<<vm.count("redundancy")<<" lastSizeRed="<<lastSizeRed<<endl;
  }
  catch (exception &ex)
  {
    cerr<<ex.what()<<endl;
    validCmd=false;
  }
  if (redundancyStr.length())
  {
    redundancy=parse_redundancy(redundancyStr);
    if (redundancy>0 && vm.count("redundancy"))
      size=0;
    else
    {
      cerr<<"Could not parse redundancy: "<<redundancyStr<<endl;
      validCmd=false;
    }
  }
  if (formatStr.length())
  {
    format=formatnum(formatStr);
    if (format<0)
      validCmd=false;
  }
  if (patternStr.length())
  {
    pattern=patternnum(patternStr);
    if (format<0)
      validCmd=false;
  }
}

I tried vm.count on "size" and "redundancy"; it returns 1 for "redundancy" regardless of whether it's specified. I tried adding a notifier to both options; it always notifies the redundancy, and notifies the redundancy first even if it's specified after the size (./propolis -s 4 -r 1/2 sets lastSizeRed to 's').

Pierre Abbat
  • 485
  • 4
  • 10

1 Answers1

0

The solution is to use an extra parser instead of a notifier. A notifier is called with the default value if the value is not specified on the command line; an extra parser is called with only the command-line options.

pair<string,string> checkSizeRed(const string &s)
{
  if (s.find("-s")==0 || s.find("--size")==0)
    lastSizeRed='s';
  if (s.find("-r")==0 || s.find("--red")==0)
    lastSizeRed='r';
  return make_pair(string(),string());
}
    po::store(po::command_line_parser(argc,argv).options(cmdline_options)
          .extra_parser(checkSizeRed).positional(p).run(),vm);

This sets lastSizeRed to 's' if --size is specified last, to 'r' if --redundancy is specified last, and to 0 if neither is specified.

Pierre Abbat
  • 485
  • 4
  • 10