// File:       poscmd02.c++
// Version:    1.00
// Author:     (c) Miles Sabin, 1997
// Purpose:    insert integral command

// Change log:
//  28/03/97   v. 1.00

#include "poscmds.h"

#include <stdio.h>       // for sprintf()
#include "ostream.h"
#include "streambuf.h"


// Implementation of InsertIntegralCommand

InsertIntegralCommand::InsertIntegralCommand(basic_ostream_char& os, long n, bool is_unsigned)
  : n_(n),
    is_unsigned_(is_unsigned)
  { execute_template(os); }

InsertIntegralCommand::~InsertIntegralCommand()
  {}

ios::iostate InsertIntegralCommand::execute(basic_ostream_char& os)
  {
    ios::fmtflags flags = os.flags();
    char* format;
    char* prefix = "";
    int prefix_width = 0;

    switch(flags&ios::basefield)
    {
      case ios::oct:
        format = "%o";
        if((flags&ios::showbase) != 0)
        {
          prefix = "0";
          prefix_width = 1;
        }
        break;

      case ios::hex:
        format = ((flags&ios::uppercase) == 0 ? "%x" : "%X");
        if((flags&ios::showbase) != 0)
        {
          prefix = ((flags&ios::uppercase) == 0 ? "0x" : "0X");
          prefix_width = 2;
        }
        break;

      default:
        format = "%u";
        if(!is_unsigned_)
        {
          if(n_ < 0)
          {
            prefix = "-";
            prefix_width = 1;
            n_ = -n_;
          }
          else if((flags&ios::showpos) != 0)
          {
            prefix = "+";
            prefix_width = 1;
          }
        }
        break;
    }

    char num[16];
    int num_width = sprintf(num, format, n_);

    int width = os.width(0);
    char fill_char = os.fill();
    int adjust = (flags&ios::adjustfield);
    basic_streambuf_char* sb = os.rdbuf();

    if(width > prefix_width+num_width && adjust != ios::left && adjust != ios::internal)
    {
      if(insert_fill(os, fill_char, width-(prefix_width+num_width)) != ios::goodbit)
        return ios::failbit;
      width = prefix_width+num_width;
    }

    if(prefix_width != 0)
    {
      if(sb->sputn(prefix, prefix_width) != prefix_width)
          return ios::failbit;
      width -= prefix_width;
    }

    if(width > num_width && adjust == ios::internal)
    {
      if(insert_fill(os, fill_char, width-num_width) != ios::goodbit)
        return ios::failbit;
      width = num_width;
    }

    if(sb->sputn(num, num_width) != num_width)
      return ios::failbit;
    width -= num_width;

    if(width > 0 && insert_fill(os, fill_char, width) != ios::goodbit)
      return ios::failbit;

    return ios::goodbit;
  }


// Implementation of basic_ostream_char

basic_ostream_char& basic_ostream_char::operator<<(short n)
  {
    InsertIntegralCommand cmd(*this, n);
    return *this;
  }

basic_ostream_char& basic_ostream_char::operator<<(unsigned short n)
  {
    InsertIntegralCommand cmd(*this, n, true);
    return *this;
  }

basic_ostream_char& basic_ostream_char::operator<<(int n)
  {
    InsertIntegralCommand cmd(*this, n);
    return *this;
  }

basic_ostream_char& basic_ostream_char::operator<<(unsigned int n)
  {
    InsertIntegralCommand cmd(*this, n, true);
    return *this;
  }

basic_ostream_char& basic_ostream_char::operator<<(long n)
  {
    InsertIntegralCommand cmd(*this, n);
    return *this;
  }

basic_ostream_char& basic_ostream_char::operator<<(unsigned long n)
  {
    InsertIntegralCommand cmd(*this, n, true);
    return *this;
  }

