<commit_before>#include "Fasta.h"
#include <stdlib.h>
#include <getopt.h>
#include "disorder.h"

void printSummary() {
    cerr << "usage: fastahack [options] <fasta reference>" << endl
         << endl
         << "options:" << endl
         << "    -i, --index          generate fasta index <fasta reference>.fai" << endl
         << "    -r, --region REGION  print the specified region" << endl
         << "    -c, --stdin          read a stream of line-delimited region specifiers on stdin" << endl
         << "                         and print the corresponding sequence for each on stdout" << endl
         //<< "    -l, --length         print the length of the specified region or sequence" << endl
         << "    -e, --entropy        print the shannon entropy of the specified region" << endl
         << endl
         << "REGION is of the form <seq>, <seq>:<start>..<end>, <seq1>:<start>..<seq2>:<end>" << endl
         << "where start and end are 1-based, and the region includes the end position." << endl
         << "Specifying a sequence name alone will return the entire sequence, specifying" << endl
         << "range will return that range, and specifying a single coordinate pair, e.g." << endl
         << "<seq>:<start> will return just that base." << endl
         << endl
         << "author: Erik Garrison <erik.garrison@bc.edu>" << endl;
}

class FastaRegion {
public:
    string startSeq;
    int startPos;
    int stopPos;

    FastaRegion(string& region) {
        startPos = -1;
        stopPos = -1;
        size_t foundFirstColon = region.find(":");
        // we only have a single string, use the whole sequence as the target
        if (foundFirstColon == string::npos) {
            startSeq = region;
        } else {
            startSeq = region.substr(0, foundFirstColon);
            size_t foundRangeDots = region.find("..", foundFirstColon);
            if (foundRangeDots == string::npos) {
                startPos = atoi(region.substr(foundFirstColon + 1).c_str());
                stopPos = startPos + 1; // just print one base if we don't give an end
            } else {
                startPos = atoi(region.substr(foundFirstColon + 1, foundRangeDots - foundRangeDots - 1).c_str());
                stopPos = atoi(region.substr(foundRangeDots + 2).c_str()); // to the start of this chromosome
            }
        }
    }

    int length(void) {
        return stopPos - startPos;
    }

};

int main (int argc, char** argv) {

    string command;
    string fastaFileName;
    string seqname;
    string longseqname;
    long long start;
    long long length;

    bool buildIndex = false;  // flag to force index building
    bool printEntropy = false;  // entropy printing
    bool readRegionsFromStdin = false;
    //bool printLength = false;
    string region;

    int c;

    while (true) {
        static struct option long_options[] =
        {
            /* These options set a flag. */
            //{"verbose", no_argument,       &verbose_flag, 1},
            //{"brief",   no_argument,       &verbose_flag, 0},
            {"help", no_argument, 0, 'h'},
            {"index",  no_argument, 0, 'i'},
            //{"length",  no_argument, &printLength, true},
            {"entropy", no_argument, 0, 'e'},
            {"region", required_argument, 0, 'r'},
            {"stdin", no_argument, 0, 'c'},
            {0, 0, 0, 0}
        };
        /* getopt_long stores the option index here. */
        int option_index = 0;

        c = getopt_long (argc, argv, "hcier:",
                         long_options, &option_index);

      /* Detect the end of the options. */
          if (c == -1)
            break;

          switch (c)
            {
            case 0:
            /* If this option set a flag, do nothing else now. */
            if (long_options[option_index].flag != 0)
              break;
            printf ("option %s", long_options[option_index].name);
            if (optarg)
              printf (" with arg %s", optarg);
            printf ("\n");
            break;

          case 'e':
            printEntropy = true;
            break;

          case 'c':
            readRegionsFromStdin = true;
            break;

          case 'i':
            buildIndex = true;
            break;

          case 'r':
            region = optarg;
            break;

          case 'h':
            printSummary();
            exit(0);
            break;

          case '?':
            /* getopt_long already printed an error message. */
            printSummary();
            exit(1);
            break;

          default:
            abort ();
          }
      }

    /* Print any remaining command line arguments (not options). */
    if (optind < argc) {
        //cerr << "fasta file: " << argv[optind] << endl;
        fastaFileName = argv[optind];
    } else {
        cerr << "please specify a fasta file" << endl;
        printSummary();
        exit(1);
    }

    if (buildIndex) {
        FastaIndex* fai = new FastaIndex();
        //cerr << "generating fasta index file for " << fastaFileName << endl;
        fai->indexReference(fastaFileName);
        fai->writeIndexFile((string) fastaFileName + fai->indexFileExtension());
    }

    string sequence;  // holds sequence so we can optionally process it

    FastaReference* fr = new FastaReference(fastaFileName);
    if (region != "") {
        FastaRegion target(region);

        if (target.startPos == -1) {
            sequence = fr->getSequence(target.startSeq);
        } else {
            sequence = fr->getSubSequence(target.startSeq, target.startPos - 1, target.length() + 1);
        }

    }

    if (readRegionsFromStdin) {
        string regionstr;
        while (getline(cin, regionstr)) {
            FastaRegion target(regionstr);
            if (target.startPos == -1) {
                cout << fr->getSequence(target.startSeq) << endl;
            } else {
                cout << fr->getSubSequence(target.startSeq, target.startPos - 1, target.length() + 1) << endl;
            }
        }
    } else {
        if (sequence != "") {
            if (printEntropy) {
                if (sequence.size() > 0) {
                    cout << shannon_H((char*) sequence.c_str(), sequence.size()) << endl;
                } else {
                    cerr << "please specify a region or sequence for which to calculate the shannon entropy" << endl;
                }
            } else {  // if no statistical processing is requested, just print the sequence
                cout << sequence << endl;
            }
        }
    }

    return 0;
}
<commit_msg>fix range specification for single-base case<commit_after>#include "Fasta.h"
#include <stdlib.h>
#include <getopt.h>
#include "disorder.h"

void printSummary() {
    cerr << "usage: fastahack [options] <fasta reference>" << endl
         << endl
         << "options:" << endl
         << "    -i, --index          generate fasta index <fasta reference>.fai" << endl
         << "    -r, --region REGION  print the specified region" << endl
         << "    -c, --stdin          read a stream of line-delimited region specifiers on stdin" << endl
         << "                         and print the corresponding sequence for each on stdout" << endl
         //<< "    -l, --length         print the length of the specified region or sequence" << endl
         << "    -e, --entropy        print the shannon entropy of the specified region" << endl
         << endl
         << "REGION is of the form <seq>, <seq>:<start>..<end>, <seq1>:<start>..<seq2>:<end>" << endl
         << "where start and end are 1-based, and the region includes the end position." << endl
         << "Specifying a sequence name alone will return the entire sequence, specifying" << endl
         << "range will return that range, and specifying a single coordinate pair, e.g." << endl
         << "<seq>:<start> will return just that base." << endl
         << endl
         << "author: Erik Garrison <erik.garrison@bc.edu>" << endl;
}

class FastaRegion {
public:
    string startSeq;
    int startPos;
    int stopPos;

    FastaRegion(string& region) {
        startPos = -1;
        stopPos = -1;
        size_t foundFirstColon = region.find(":");
        // we only have a single string, use the whole sequence as the target
        if (foundFirstColon == string::npos) {
            startSeq = region;
        } else {
            startSeq = region.substr(0, foundFirstColon);
            size_t foundRangeDots = region.find("..", foundFirstColon);
            if (foundRangeDots == string::npos) {
                startPos = atoi(region.substr(foundFirstColon + 1).c_str());
                stopPos = startPos; // just print one base if we don't give an end
            } else {
                startPos = atoi(region.substr(foundFirstColon + 1, foundRangeDots - foundRangeDots - 1).c_str());
                stopPos = atoi(region.substr(foundRangeDots + 2).c_str()); // to the start of this chromosome
            }
        }
    }

    int length(void) {
        if (stopPos > 0) {
            return stopPos - startPos + 1;
        } else {
            return 1;
        }
    }

};

int main (int argc, char** argv) {

    string command;
    string fastaFileName;
    string seqname;
    string longseqname;
    long long start;
    long long length;

    bool buildIndex = false;  // flag to force index building
    bool printEntropy = false;  // entropy printing
    bool readRegionsFromStdin = false;
    //bool printLength = false;
    string region;

    int c;

    while (true) {
        static struct option long_options[] =
        {
            /* These options set a flag. */
            //{"verbose", no_argument,       &verbose_flag, 1},
            //{"brief",   no_argument,       &verbose_flag, 0},
            {"help", no_argument, 0, 'h'},
            {"index",  no_argument, 0, 'i'},
            //{"length",  no_argument, &printLength, true},
            {"entropy", no_argument, 0, 'e'},
            {"region", required_argument, 0, 'r'},
            {"stdin", no_argument, 0, 'c'},
            {0, 0, 0, 0}
        };
        /* getopt_long stores the option index here. */
        int option_index = 0;

        c = getopt_long (argc, argv, "hcier:",
                         long_options, &option_index);

      /* Detect the end of the options. */
          if (c == -1)
            break;

          switch (c)
            {
            case 0:
            /* If this option set a flag, do nothing else now. */
            if (long_options[option_index].flag != 0)
              break;
            printf ("option %s", long_options[option_index].name);
            if (optarg)
              printf (" with arg %s", optarg);
            printf ("\n");
            break;

          case 'e':
            printEntropy = true;
            break;

          case 'c':
            readRegionsFromStdin = true;
            break;

          case 'i':
            buildIndex = true;
            break;

          case 'r':
            region = optarg;
            break;

          case 'h':
            printSummary();
            exit(0);
            break;

          case '?':
            /* getopt_long already printed an error message. */
            printSummary();
            exit(1);
            break;

          default:
            abort ();
          }
      }

    /* Print any remaining command line arguments (not options). */
    if (optind < argc) {
        //cerr << "fasta file: " << argv[optind] << endl;
        fastaFileName = argv[optind];
    } else {
        cerr << "please specify a fasta file" << endl;
        printSummary();
        exit(1);
    }

    if (buildIndex) {
        FastaIndex* fai = new FastaIndex();
        //cerr << "generating fasta index file for " << fastaFileName << endl;
        fai->indexReference(fastaFileName);
        fai->writeIndexFile((string) fastaFileName + fai->indexFileExtension());
    }

    string sequence;  // holds sequence so we can optionally process it

    FastaReference* fr = new FastaReference(fastaFileName);
    if (region != "") {
        FastaRegion target(region);

        if (target.startPos == -1) {
            sequence = fr->getSequence(target.startSeq);
        } else {
            sequence = fr->getSubSequence(target.startSeq, target.startPos - 1, target.length());
        }

    }

    if (readRegionsFromStdin) {
        string regionstr;
        while (getline(cin, regionstr)) {
            FastaRegion target(regionstr);
            if (target.startPos == -1) {
                cout << fr->getSequence(target.startSeq) << endl;
            } else {
                cout << fr->getSubSequence(target.startSeq, target.startPos - 1, target.length()) << endl;
            }
        }
    } else {
        if (sequence != "") {
            if (printEntropy) {
                if (sequence.size() > 0) {
                    cout << shannon_H((char*) sequence.c_str(), sequence.size()) << endl;
                } else {
                    cerr << "please specify a region or sequence for which to calculate the shannon entropy" << endl;
                }
            } else {  // if no statistical processing is requested, just print the sequence
                cout << sequence << endl;
            }
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "Fasta.h"

void printSummary() {
    cerr << "usage: fastahack <command> [options]" << endl
         << "actions:" << endl
         << "    index <fasta reference> <sequence name>" << endl
         << "    sequence <fasta reference> <sequence name>" << endl
         << "    subsequence <fasta reference> <sequence name> <start> <length>" << endl;
}

int main (int argc, char** argv) {

    string command;
    string fastaFileName;
    string seqname;
    string longseqname;
    long long start;
    long long length;

    if (!argv[1]) {
        printSummary();
        exit(0);
    } else {
        command = argv[1];
    }

    if (!argv[2]) {
        cerr << "please provide a fasta reference filename" << endl;
        exit(1);
    } else {
        fastaFileName = argv[2];
    }

    if (command == "index") {
        FastaReference* fr = new FastaReference(fastaFileName);
        /*FastaIndex* fai = new FastaIndex();
        cerr << "generating fasta index file from " << fastaFileName << endl;
        fai->indexReference(fastaFileName);
        fai->writeIndexFile((string) fastaFileName + fai->indexFileExtension());
        */
    } else {
        if (!argv[3]) {
            cerr << "please specify the name of a sequence to print" << endl;
            exit(1);
        } else {
            seqname = argv[3];
        }
        FastaReference* fr = new FastaReference(fastaFileName);
        if (fr->index->find(seqname) == fr->index->end()) {
            longseqname = fr->sequenceNameStartingWith(seqname);
        } else {
            longseqname = seqname;
        }
        if (longseqname == "") {
            cerr << "could not find sequence in reference " << fastaFileName <<
                " named or starting with " << seqname << endl;
            exit(1);
        }

        if (command == "sequence") {
            cout << fr->getSequence(longseqname) << endl;
        } else if (command == "subsequence") {
            if (!argv[4] || !argv[5]) {
                cerr << "no subsequence boundaries specified" << endl;
                exit(1);
            } else {
                start = lexical_cast<long long>(argv[4]);
                length = lexical_cast<long long>(argv[5]);
            }
            cout << fr->getSubSequence(longseqname, start, length) << endl;
        }
    }
    return 0;
}
<commit_msg>minor change to help printout<commit_after>#include "Fasta.h"

void printSummary() {
    cerr << "usage: fastahack <command> [options]" << endl
         << "actions:" << endl
         << "    index <fasta reference>" << endl
         << "    sequence <fasta reference> <sequence name>" << endl
         << "    subsequence <fasta reference> <sequence name> <start> <length>" << endl;
}

int main (int argc, char** argv) {

    string command;
    string fastaFileName;
    string seqname;
    string longseqname;
    long long start;
    long long length;

    if (!argv[1]) {
        printSummary();
        exit(0);
    } else {
        command = argv[1];
    }

    if (!argv[2]) {
        cerr << "please provide a fasta reference filename" << endl;
        exit(1);
    } else {
        fastaFileName = argv[2];
    }

    if (command == "index") {
        FastaReference* fr = new FastaReference(fastaFileName);
        /*FastaIndex* fai = new FastaIndex();
        cerr << "generating fasta index file from " << fastaFileName << endl;
        fai->indexReference(fastaFileName);
        fai->writeIndexFile((string) fastaFileName + fai->indexFileExtension());
        */
    } else {
        if (!argv[3]) {
            cerr << "please specify the name of a sequence to print" << endl;
            exit(1);
        } else {
            seqname = argv[3];
        }
        FastaReference* fr = new FastaReference(fastaFileName);
        if (fr->index->find(seqname) == fr->index->end()) {
            longseqname = fr->sequenceNameStartingWith(seqname);
        } else {
            longseqname = seqname;
        }
        if (longseqname == "") {
            cerr << "could not find sequence in reference " << fastaFileName <<
                " named or starting with " << seqname << endl;
            exit(1);
        }

        if (command == "sequence") {
            cout << fr->getSequence(longseqname) << endl;
        } else if (command == "subsequence") {
            if (!argv[4] || !argv[5]) {
                cerr << "no subsequence boundaries specified" << endl;
                exit(1);
            } else {
                start = lexical_cast<long long>(argv[4]);
                length = lexical_cast<long long>(argv[5]);
            }
            cout << fr->getSubSequence(longseqname, start, length) << endl;
        }
    }
    return 0;
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 1998, 1999 by Nathaniel 'NooTe' Saint Martin
    Copyright (C) 1998, 1999 by Jorrit Tyberghein
    Written by Nathaniel 'NooTe' Saint Martin

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "isound/listener.h"
#include "isound/data.h"
#include "srdrsrc.h"
#include "srdrcom.h"
#include "sndhdl.h"
#include "qsqrt.h"

SCF_IMPLEMENT_IBASE(csSoundSourceSoftware)
  SCF_IMPLEMENTS_INTERFACE(iSoundSource)
SCF_IMPLEMENT_IBASE_END;

csSoundSourceSoftware::csSoundSourceSoftware(csSoundRenderSoftware *srdr,
    csSoundHandleSoftware *hdl, int m3d)
{
  SCF_CONSTRUCT_IBASE(hdl);

  SoundRender = srdr;
  FrequencyFactor = 1;
  Volume = 1.0;
  Mode3d = m3d;
  Position = csVector3(0,0,0);
  Velocity = csVector3(0,0,0);
  Active = false;
  SoundPos = 0;
  SoundHandle = hdl;
}

csSoundSourceSoftware::~csSoundSourceSoftware()
{
}

void csSoundSourceSoftware::Play(unsigned long pMethod)
{
  PlayMethod=pMethod;
  if (!Active){ Active=true; SoundRender->AddSource(this); }
  if (PlayMethod & SOUND_RESTART) Restart();
}

void csSoundSourceSoftware::Stop()
{
  if (Active)
  {
    SoundRender->RemoveSource(this);
    Active=false;
  }
}

void csSoundSourceSoftware::Restart()
{
  if (!SoundHandle->Data) return;
  if (SoundHandle->Data->IsStatic())
    SoundPos = 0;
  else
    SoundHandle->Data->ResetStreamed();
}

bool csSoundSourceSoftware::IsActive()
{
  return Active;
}

void csSoundSourceSoftware::SetVolume(float vol)
{
  Volume = vol;
}

float csSoundSourceSoftware::GetVolume()
{
  return Volume;
}

void csSoundSourceSoftware::SetFrequencyFactor(float factor)
{
  FrequencyFactor = factor;
}

float csSoundSourceSoftware::GetFrequencyFactor()
{
  return FrequencyFactor;
}

int csSoundSourceSoftware::GetMode3D()
{
  return Mode3d;
}

void csSoundSourceSoftware::SetMode3D(int m3d)
{
  Mode3d = m3d;
}

void csSoundSourceSoftware::SetPosition(csVector3 pos)
{
  Position=pos;
}

csVector3 csSoundSourceSoftware::GetPosition()
{
  return Position;
}

void csSoundSourceSoftware::SetVelocity(csVector3 v)
{
  Velocity=v;
}

csVector3 csSoundSourceSoftware::GetVelocity()
{
  return Velocity;
}

void csSoundSourceSoftware::Prepare(float BaseVolume)
{
  // frequency
  CalcFreqFactor=FrequencyFactor;

  // volume
  CalcVolL = CalcVolR = Volume*BaseVolume;

  // for non-3d sources we don't calculate anything else
  if (Mode3d == SOUND3D_DISABLE) return;

  // get the global listener object
  iSoundListener *Listener=SoundRender->GetListener();

  // position of the listener's ears
  csVector3 EarL,EarR;

  if (Mode3d == SOUND3D_RELATIVE)
  {
    // position of the sound is relative to the listener, so we simply
    // place the listener at (0,0,0) with front (0,0,1) and top (0,1,0)
    EarL = csVector3(-Listener->GetHeadSize()/2, 0, 0);
    EarR = csVector3(+Listener->GetHeadSize()/2, 0, 0);
  }
  else
  {
    // calculate the 'left' vector
    csVector3 Front,Top,Left;
    Listener->GetDirection(Front,Top);
    Left=Top%Front;
    if (Left.Norm()<EPSILON)
    {
      // user has supplied bad front and top vectors
      CalcVolL = CalcVolR = 0;
      return;
    } else Left.Normalize();

    // calculate ear position
    EarL=Listener->GetPosition()+Left*Listener->GetHeadSize()/2;
    EarR=Listener->GetPosition()-Left*Listener->GetHeadSize()/2;
  }

  // calculate ear distance
  float DistL,DistR;
  DistL=(EarL-Position).Norm();
  DistR=(EarR-Position).Norm();

  // the following tests should not be deleted until we see (or hear)
  // what gives the best results. Just try it!

  // @@@ test: amplify difference between ears.
//  float d=DistL-DistR;
//  DistL+=2*d;
//  DistR-=2*d;

  // @@@ test: take square root of distance. Otherwise the missile sound
  // in walktest seems to become distant too fast.
//  DistL=sqrt(DistL);
//  DistR=sqrt(DistR);

  // prevent too near sounds
  if (DistL<1) DistL=1;
  if (DistR<1) DistR=1;

  // calculate ear volume
  float DistFactor=Listener->GetDistanceFactor();
  CalcVolL/=DistL*DistFactor;
  CalcVolR/=DistR*DistFactor;
}

/* helper macros */
#define READMONOSAMP        ((int)(Input[i])-NullSample)
#define READLEFTSAMP        ((int)(Input[2*i])-NullSample)
#define READRIGHTSAMP       ((int)(Input[2*i+1])-NullSample)

#define WRITEMONOSAMP(x)    Output[i]+=(stype)((x)*(CalcVolL+CalcVolR)/2);
#define WRITELEFTSAMP(x)    Output[2*i]+=(stype)((x)*CalcVolL);
#define WRITERIGHTSAMP(x)   Output[2*i+1]+=(stype)((x)*CalcVolR);

#define READMONO3D          int samp=READMONOSAMP;
#define READSTEREO3D        int samp=(READLEFTSAMP+READRIGHTSAMP)/2;

#define WRITEMONO3D         WRITEMONOSAMP(samp);
#define WRITESTEREO3D       {WRITELEFTSAMP(samp); WRITERIGHTSAMP(samp);}

#define LOOP                for (long i=0;i<NumSamples;i++)

#define ADDTOBUFFER_BITS {                                              \
  stype *Input = (stype*)Source;                                        \
  stype *Output = (stype*)Dest;                                         \
                                                                        \
  if (Mode3d != SOUND3D_DISABLE) {                                      \
    /* is 3d effect is enabled, stereo input channels are mixed */      \
    if (InputFormat->Channels==2) {                                     \
      if (OutputFormat->Channels==2) {                                  \
        LOOP {READSTEREO3D; WRITESTEREO3D;}                             \
      } else {                                                          \
        LOOP {READSTEREO3D; WRITEMONO3D;}                               \
      }                                                                 \
    } else {                                                            \
      if (OutputFormat->Channels==2) {                                  \
        LOOP {READMONO3D; WRITESTEREO3D;}                               \
      } else {                                                          \
        LOOP {READMONO3D; WRITEMONO3D;}                                 \
      }                                                                 \
    }                                                                   \
  } else {                                                              \
    /* handle non-3d sound (use CalcVolL for volume, NOT 'Volume', */   \
    /* to use any precalculation done in Prepare()                 */   \
    if (InputFormat->Channels==2) {                                     \
      if (OutputFormat->Channels==2) {                                  \
        /* stereo -> stereo */                                          \
        LOOP {                                                          \
          WRITELEFTSAMP(READLEFTSAMP);                                  \
          WRITERIGHTSAMP(READRIGHTSAMP);                                \
        }                                                               \
      } else {                                                          \
        /* stereo -> mono */                                            \
        LOOP {                                                          \
          WRITEMONOSAMP((READLEFTSAMP + READRIGHTSAMP)/2);              \
        }                                                               \
      }                                                                 \
    } else {                                                            \
      if (OutputFormat->Channels==2) {                                  \
        /* mono -> stereo */                                            \
        LOOP {                                                          \
          WRITELEFTSAMP(READMONOSAMP);                                  \
          WRITERIGHTSAMP(READMONOSAMP);                                 \
        }                                                               \
      } else {                                                          \
        LOOP {                                                          \
        /* mono -> mono */                                              \
          WRITEMONOSAMP(READMONOSAMP);                                  \
        }                                                               \
      }                                                                 \
    }                                                                   \
  }                                                                     \
}

void csSoundSourceSoftware::WriteBuffer(const void *Source, void *Dest,
        long NumSamples)
{
  csSoundFormat outfmt;
  outfmt.Freq = SoundRender->getFrequency();
  outfmt.Bits = SoundRender->is16Bits() ? 16 : 8;
  outfmt.Channels = SoundRender->isStereo() ? 2 : 1;

  const csSoundFormat *InputFormat = SoundHandle->Data->GetFormat();
  const csSoundFormat *OutputFormat = &outfmt;

  if (OutputFormat->Bits == 16)
  {
    #define stype short
    #define NullSample 0
    ADDTOBUFFER_BITS
    #undef stype
    #undef NullSample
  }
  else
  {
    #define stype unsigned char
    #define NullSample 128
    ADDTOBUFFER_BITS
    #undef stype
    #undef NullSample
  }
}

void csSoundSourceSoftware::AddToBufferStatic(void *mem, long size)
{
  iSoundData *snd = SoundHandle->Data;
  if (!snd) return;

  long InBPS = (snd->GetFormat()->Bits/8) * (snd->GetFormat()->Channels);
  long OutBPS = (SoundRender->is16Bits() ? 2 : 1) *
                (SoundRender->isStereo() ? 2 : 1);
  long NumSamples = size / OutBPS;

  if (snd->IsStatic ())
    while (1)
    {
      long Num = NumSamples;

      if (SoundPos + Num > snd->GetStaticSampleCount())
	Num = snd->GetStaticSampleCount() - SoundPos;
      unsigned char *Input = (unsigned char*)snd->GetStaticData();

      WriteBuffer(Input + SoundPos * InBPS, mem, Num);
      SoundPos += Num;

      NumSamples -= Num;
      mem = ((unsigned char *)mem) + Num * OutBPS;

      if (NumSamples == 0) break;
      if (!(PlayMethod & SOUND_LOOP)) break;
      Restart();
    }
  else // streamed sound
  {
    long wait = 0;
    while (1)
    {
      long Num = NumSamples;

      void *Buffer = snd->ReadStreamed (Num);
      if (Num)
      {
	WriteBuffer(Buffer, mem, Num);
	NumSamples -= Num;
	mem = ((unsigned char *)mem) + Num * OutBPS;
      }
      if (NumSamples == 0) break;

      if (Num == 0)
      {
	if (wait == 0)
	{
	  Restart();
	  wait++;
	}
	else
	  break;
      }
    }
  }
}

<commit_msg>fixed long standing bug where non looping static sounds were never removed<commit_after>/*
    Copyright (C) 1998, 1999 by Nathaniel 'NooTe' Saint Martin
    Copyright (C) 1998, 1999 by Jorrit Tyberghein
    Written by Nathaniel 'NooTe' Saint Martin

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "isound/listener.h"
#include "isound/data.h"
#include "srdrsrc.h"
#include "srdrcom.h"
#include "sndhdl.h"
#include "qsqrt.h"

SCF_IMPLEMENT_IBASE(csSoundSourceSoftware)
  SCF_IMPLEMENTS_INTERFACE(iSoundSource)
SCF_IMPLEMENT_IBASE_END;

csSoundSourceSoftware::csSoundSourceSoftware(csSoundRenderSoftware *srdr,
    csSoundHandleSoftware *hdl, int m3d)
{
  SCF_CONSTRUCT_IBASE(hdl);

  SoundRender = srdr;
  FrequencyFactor = 1;
  Volume = 1.0;
  Mode3d = m3d;
  Position = csVector3(0,0,0);
  Velocity = csVector3(0,0,0);
  Active = false;
  SoundPos = 0;
  SoundHandle = hdl;
}

csSoundSourceSoftware::~csSoundSourceSoftware()
{
}

void csSoundSourceSoftware::Play(unsigned long pMethod)
{
  PlayMethod=pMethod;
  if (!Active){ Active=true; SoundRender->AddSource(this); }
  if (PlayMethod & SOUND_RESTART) Restart();
}

void csSoundSourceSoftware::Stop()
{
  if (Active)
  {
    SoundRender->RemoveSource(this);
    Active=false;
  }
}

void csSoundSourceSoftware::Restart()
{
  if (!SoundHandle->Data) return;
  if (SoundHandle->Data->IsStatic())
    SoundPos = 0;
  else
    SoundHandle->Data->ResetStreamed();
}

bool csSoundSourceSoftware::IsActive()
{
  return Active;
}

void csSoundSourceSoftware::SetVolume(float vol)
{
  Volume = vol;
}

float csSoundSourceSoftware::GetVolume()
{
  return Volume;
}

void csSoundSourceSoftware::SetFrequencyFactor(float factor)
{
  FrequencyFactor = factor;
}

float csSoundSourceSoftware::GetFrequencyFactor()
{
  return FrequencyFactor;
}

int csSoundSourceSoftware::GetMode3D()
{
  return Mode3d;
}

void csSoundSourceSoftware::SetMode3D(int m3d)
{
  Mode3d = m3d;
}

void csSoundSourceSoftware::SetPosition(csVector3 pos)
{
  Position=pos;
}

csVector3 csSoundSourceSoftware::GetPosition()
{
  return Position;
}

void csSoundSourceSoftware::SetVelocity(csVector3 v)
{
  Velocity=v;
}

csVector3 csSoundSourceSoftware::GetVelocity()
{
  return Velocity;
}

void csSoundSourceSoftware::Prepare(float BaseVolume)
{
  // frequency
  CalcFreqFactor=FrequencyFactor;

  // volume
  CalcVolL = CalcVolR = Volume*BaseVolume;

  // for non-3d sources we don't calculate anything else
  if (Mode3d == SOUND3D_DISABLE) return;

  // get the global listener object
  iSoundListener *Listener=SoundRender->GetListener();

  // position of the listener's ears
  csVector3 EarL,EarR;

  if (Mode3d == SOUND3D_RELATIVE)
  {
    // position of the sound is relative to the listener, so we simply
    // place the listener at (0,0,0) with front (0,0,1) and top (0,1,0)
    EarL = csVector3(-Listener->GetHeadSize()/2, 0, 0);
    EarR = csVector3(+Listener->GetHeadSize()/2, 0, 0);
  }
  else
  {
    // calculate the 'left' vector
    csVector3 Front,Top,Left;
    Listener->GetDirection(Front,Top);
    Left=Top%Front;
    if (Left.Norm()<EPSILON)
    {
      // user has supplied bad front and top vectors
      CalcVolL = CalcVolR = 0;
      return;
    } else Left.Normalize();

    // calculate ear position
    EarL=Listener->GetPosition()+Left*Listener->GetHeadSize()/2;
    EarR=Listener->GetPosition()-Left*Listener->GetHeadSize()/2;
  }

  // calculate ear distance
  float DistL,DistR;
  DistL=(EarL-Position).Norm();
  DistR=(EarR-Position).Norm();

  // the following tests should not be deleted until we see (or hear)
  // what gives the best results. Just try it!

  // @@@ test: amplify difference between ears.
//  float d=DistL-DistR;
//  DistL+=2*d;
//  DistR-=2*d;

  // @@@ test: take square root of distance. Otherwise the missile sound
  // in walktest seems to become distant too fast.
//  DistL=sqrt(DistL);
//  DistR=sqrt(DistR);

  // prevent too near sounds
  if (DistL<1) DistL=1;
  if (DistR<1) DistR=1;

  // calculate ear volume
  float DistFactor=Listener->GetDistanceFactor();
  CalcVolL/=DistL*DistFactor;
  CalcVolR/=DistR*DistFactor;
}

/* helper macros */
#define READMONOSAMP        ((int)(Input[i])-NullSample)
#define READLEFTSAMP        ((int)(Input[2*i])-NullSample)
#define READRIGHTSAMP       ((int)(Input[2*i+1])-NullSample)

#define WRITEMONOSAMP(x)    Output[i]+=(stype)((x)*(CalcVolL+CalcVolR)/2);
#define WRITELEFTSAMP(x)    Output[2*i]+=(stype)((x)*CalcVolL);
#define WRITERIGHTSAMP(x)   Output[2*i+1]+=(stype)((x)*CalcVolR);

#define READMONO3D          int samp=READMONOSAMP;
#define READSTEREO3D        int samp=(READLEFTSAMP+READRIGHTSAMP)/2;

#define WRITEMONO3D         WRITEMONOSAMP(samp);
#define WRITESTEREO3D       {WRITELEFTSAMP(samp); WRITERIGHTSAMP(samp);}

#define LOOP                for (long i=0;i<NumSamples;i++)

#define ADDTOBUFFER_BITS {                                              \
  stype *Input = (stype*)Source;                                        \
  stype *Output = (stype*)Dest;                                         \
                                                                        \
  if (Mode3d != SOUND3D_DISABLE) {                                      \
    /* is 3d effect is enabled, stereo input channels are mixed */      \
    if (InputFormat->Channels==2) {                                     \
      if (OutputFormat->Channels==2) {                                  \
        LOOP {READSTEREO3D; WRITESTEREO3D;}                             \
      } else {                                                          \
        LOOP {READSTEREO3D; WRITEMONO3D;}                               \
      }                                                                 \
    } else {                                                            \
      if (OutputFormat->Channels==2) {                                  \
        LOOP {READMONO3D; WRITESTEREO3D;}                               \
      } else {                                                          \
        LOOP {READMONO3D; WRITEMONO3D;}                                 \
      }                                                                 \
    }                                                                   \
  } else {                                                              \
    /* handle non-3d sound (use CalcVolL for volume, NOT 'Volume', */   \
    /* to use any precalculation done in Prepare()                 */   \
    if (InputFormat->Channels==2) {                                     \
      if (OutputFormat->Channels==2) {                                  \
        /* stereo -> stereo */                                          \
        LOOP {                                                          \
          WRITELEFTSAMP(READLEFTSAMP);                                  \
          WRITERIGHTSAMP(READRIGHTSAMP);                                \
        }                                                               \
      } else {                                                          \
        /* stereo -> mono */                                            \
        LOOP {                                                          \
          WRITEMONOSAMP((READLEFTSAMP + READRIGHTSAMP)/2);              \
        }                                                               \
      }                                                                 \
    } else {                                                            \
      if (OutputFormat->Channels==2) {                                  \
        /* mono -> stereo */                                            \
        LOOP {                                                          \
          WRITELEFTSAMP(READMONOSAMP);                                  \
          WRITERIGHTSAMP(READMONOSAMP);                                 \
        }                                                               \
      } else {                                                          \
        LOOP {                                                          \
        /* mono -> mono */                                              \
          WRITEMONOSAMP(READMONOSAMP);                                  \
        }                                                               \
      }                                                                 \
    }                                                                   \
  }                                                                     \
}

void csSoundSourceSoftware::WriteBuffer(const void *Source, void *Dest,
        long NumSamples)
{
  csSoundFormat outfmt;
  outfmt.Freq = SoundRender->getFrequency();
  outfmt.Bits = SoundRender->is16Bits() ? 16 : 8;
  outfmt.Channels = SoundRender->isStereo() ? 2 : 1;

  const csSoundFormat *InputFormat = SoundHandle->Data->GetFormat();
  const csSoundFormat *OutputFormat = &outfmt;

  if (OutputFormat->Bits == 16)
  {
    #define stype short
    #define NullSample 0
    ADDTOBUFFER_BITS
    #undef stype
    #undef NullSample
  }
  else
  {
    #define stype unsigned char
    #define NullSample 128
    ADDTOBUFFER_BITS
    #undef stype
    #undef NullSample
  }
}

void csSoundSourceSoftware::AddToBufferStatic(void *mem, long size)
{
  iSoundData *snd = SoundHandle->Data;
  if (!snd) return;

  long InBPS = (snd->GetFormat()->Bits/8) * (snd->GetFormat()->Channels);
  long OutBPS = (SoundRender->is16Bits() ? 2 : 1) *
                (SoundRender->isStereo() ? 2 : 1);
  long NumSamples = size / OutBPS;

  if (snd->IsStatic ())
    while (1)
    {
      long Num = NumSamples;

      if (SoundPos + Num > snd->GetStaticSampleCount())
	Num = snd->GetStaticSampleCount() - SoundPos;
      unsigned char *Input = (unsigned char*)snd->GetStaticData();

      WriteBuffer(Input + SoundPos * InBPS, mem, Num);
      SoundPos += Num;

      NumSamples -= Num;
      mem = ((unsigned char *)mem) + Num * OutBPS;
      if (NumSamples == 0) break;
      if (!(PlayMethod & SOUND_LOOP))
      {
	Active = (SoundPos  < snd->GetStaticSampleCount());
	break;
      }
      Restart();
    }
  else // streamed sound
  {
    long wait = 0;
    while (1)
    {
      long Num = NumSamples;

      void *Buffer = snd->ReadStreamed (Num);
      if (Num)
      {
	WriteBuffer(Buffer, mem, Num);
	NumSamples -= Num;
	mem = ((unsigned char *)mem) + Num * OutBPS;
      }
      if (NumSamples == 0) break;

      if (Num == 0)
      {
	if (wait == 0)
	{
	  Restart();
	  wait++;
	}
	else
	  break;
      }
    }
  }
}

<|endoftext|>


<commit_before>// $Id$ //
// Category: geometry
//
// See the class description in the header file.

#include "AliSensitiveDetector.h"
#include "AliModule.h"
#include "AliRun.h"

#include "TG3Units.h"

AliSensitiveDetector::AliSensitiveDetector(G4String sdName, AliModule* module)
  : TG4VSensitiveDetector(sdName),
    fModule(module)
{
//
}

AliSensitiveDetector::AliSensitiveDetector(G4String sdName, AliModule* module,
                                           G4int id)
  : TG4VSensitiveDetector(sdName, id),
    fModule(module)
{
//
}

AliSensitiveDetector::AliSensitiveDetector(const AliSensitiveDetector& right)
  : TG4VSensitiveDetector(right)
{
//
  fModule = right.fModule;
}

AliSensitiveDetector::AliSensitiveDetector(){
//
}

AliSensitiveDetector::~AliSensitiveDetector() {
//
}

// operators

AliSensitiveDetector&
AliSensitiveDetector::operator=(const AliSensitiveDetector& right)
{
  // check assignement to self
  if (this == &right) return *this;

  // base class assignement
  TG4VSensitiveDetector::operator=(right);

  fModule = right.fModule;

  return *this;
}

// public methods

void AliSensitiveDetector::UserProcessHits(const G4Track* track,
                                           const G4Step* step)
{
// Calls StepManager of associated AliModule.
// ---

  // add energy deposit of the current step
  // directly to AliRun
  if (step)
    gAlice->AddEnergyDeposit(
      fID, step->GetTotalEnergyDeposit()/TG3Units::Energy());

  // let AliModule process the step
  fModule->StepManager();
}

<commit_msg>added Initialize() method; added call to AliMCQA::StepManager in UserProcessHits()<commit_after>// $Id$ //
// Category: geometry
//
// See the class description in the header file.

#include "AliSensitiveDetector.h"
#include "AliModule.h"
#include "AliRun.h"
#include "AliMCQA.h"

#include "TG3Units.h"

AliSensitiveDetector::AliSensitiveDetector(G4String sdName, AliModule* module)
  : TG4VSensitiveDetector(sdName),
    fModule(module),
    fModuleID(0),
    fMCQA(0)
{
//
}

AliSensitiveDetector::AliSensitiveDetector(G4String sdName, AliModule* module,
                                           G4int id)
  : TG4VSensitiveDetector(sdName, id),
    fModule(module),
    fModuleID(0),
    fMCQA(0)
{
//
}

AliSensitiveDetector::AliSensitiveDetector(const AliSensitiveDetector& right)
  : TG4VSensitiveDetector(right)
{
//
  fModule = right.fModule;
}

AliSensitiveDetector::AliSensitiveDetector(){
//
}

AliSensitiveDetector::~AliSensitiveDetector() {
//
}

// operators

AliSensitiveDetector&
AliSensitiveDetector::operator=(const AliSensitiveDetector& right)
{
  // check assignement to self
  if (this == &right) return *this;

  // base class assignement
  TG4VSensitiveDetector::operator=(right);

  fModule = right.fModule;

  return *this;
}

// public methods

void AliSensitiveDetector::Initialize(G4HCofThisEvent*HCE)
{
// This method is called by G4 kernel at the beginning of event action
// before user defined BeginOfEventAction() method.
// ---

  fModuleID = gAlice->GetModuleID(fModule->GetName());
  fMCQA = gAlice->GetMCQA();
}

void AliSensitiveDetector::UserProcessHits(const G4Track* track,
                                           const G4Step* step)
{
// Calls StepManager of associated AliModule.
// ---

  // add energy deposit of the current step
  // directly to AliRun
  if (step)
    gAlice->AddEnergyDeposit(
      fID, step->GetTotalEnergyDeposit()/TG3Units::Energy());

  fMCQA->StepManager(fModuleID);

  // let AliModule process the step
  fModule->StepManager();
}

<|endoftext|>


<commit_before>//
//  Disk.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 13/09/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#include "Disk.hpp"
#include "../../../Storage/Disk/Controller/DiskController.hpp"
#include "../../../Storage/Disk/Encodings/CommodoreGCR.hpp"
#include "../../../Storage/Data/Commodore.hpp"

#include <limits>
#include <vector>
#include <array>

using namespace Analyser::Static::Commodore;

class CommodoreGCRParser: public Storage::Disk::Controller {
	public:
		std::shared_ptr<Storage::Disk::Drive> drive;

		CommodoreGCRParser() : Storage::Disk::Controller(4000000), shift_register_(0), track_(1) {
			emplace_drive(4000000, 300, 2);
			set_drive(1);
			drive->set_motor_on(true);
		}

		struct Sector {
			uint8_t sector, track;
			std::array<uint8_t, 256> data;
			bool header_checksum_matched;
			bool data_checksum_matched;
		};

		/*!
			Attempts to read the sector located at @c track and @c sector.

			@returns a sector if one was found; @c nullptr otherwise.
		*/
		std::shared_ptr<Sector> get_sector(uint8_t track, uint8_t sector) {
			int difference = static_cast<int>(track) - static_cast<int>(track_);
			track_ = track;

			if(difference) {
				int direction = difference < 0 ? -1 : 1;
				difference *= direction;

				for(int c = 0; c < difference; c++) {
					get_drive().step(Storage::Disk::HeadPosition(direction));
				}

				unsigned int zone = 3;
				if(track >= 18) zone = 2;
				else if(track >= 25) zone = 1;
				else if(track >= 31) zone = 0;
				set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(zone));
			}

			return get_sector(sector);
		}

	private:
		unsigned int shift_register_;
		int index_count_;
		int bit_count_;
		uint8_t track_;
		std::shared_ptr<Sector> sector_cache_[65536];

		void process_input_bit(int value) {
			shift_register_ = ((shift_register_ << 1) | static_cast<unsigned int>(value)) & 0x3ff;
			bit_count_++;
		}

		unsigned int proceed_to_next_block(int max_index_count) {
			// find GCR lead-in
			proceed_to_shift_value(0x3ff);
			if(shift_register_ != 0x3ff) return 0xff;

			// find end of lead-in
			while(shift_register_ == 0x3ff && index_count_ < max_index_count) {
				run_for(Cycles(1));
			}

			// continue for a further nine bits
			bit_count_ = 0;
			while(bit_count_ < 9 && index_count_ < max_index_count) {
				run_for(Cycles(1));
			}

			return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
		}

		unsigned int get_next_byte() {
			bit_count_ = 0;
			while(bit_count_ < 10) run_for(Cycles(1));
			return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
		}

		void proceed_to_shift_value(unsigned int shift_value) {
			const int max_index_count = index_count_ + 2;
			while(shift_register_ != shift_value && index_count_ < max_index_count) {
				run_for(Cycles(1));
			}
		}

		void process_index_hole() {
			index_count_++;
		}

		std::shared_ptr<Sector> get_sector(uint8_t sector) {
			uint16_t sector_address = static_cast<uint16_t>((track_ << 8) | sector);
			if(sector_cache_[sector_address]) return sector_cache_[sector_address];

			std::shared_ptr<Sector> first_sector = get_next_sector();
			if(!first_sector) return first_sector;
			if(first_sector->sector == sector) return first_sector;

			while(1) {
				std::shared_ptr<Sector> next_sector = get_next_sector();
				if(next_sector->sector == first_sector->sector) return nullptr;
				if(next_sector->sector == sector) return next_sector;
			}
		}

		std::shared_ptr<Sector> get_next_sector() {
			auto sector = std::make_shared<Sector>();
			const int max_index_count = index_count_ + 2;

			while(index_count_ < max_index_count) {
				// look for a sector header
				while(1) {
					if(proceed_to_next_block(max_index_count) == 0x08) break;
					if(index_count_ >= max_index_count) return nullptr;
				}

				// get sector details, skip if this looks malformed
				uint8_t checksum = static_cast<uint8_t>(get_next_byte());
				sector->sector = static_cast<uint8_t>(get_next_byte());
				sector->track = static_cast<uint8_t>(get_next_byte());
				uint8_t disk_id[2];
				disk_id[0] = static_cast<uint8_t>(get_next_byte());
				disk_id[1] = static_cast<uint8_t>(get_next_byte());
				if(checksum != (sector->sector ^ sector->track ^ disk_id[0] ^ disk_id[1])) continue;

				// look for the following data
				while(1) {
					if(proceed_to_next_block(max_index_count) == 0x07) break;
					if(index_count_ >= max_index_count) return nullptr;
				}

				checksum = 0;
				for(std::size_t c = 0; c < 256; c++) {
					sector->data[c] = static_cast<uint8_t>(get_next_byte());
					checksum ^= sector->data[c];
				}

				if(checksum == get_next_byte()) {
					uint16_t sector_address = static_cast<uint16_t>((sector->track << 8) | sector->sector);
					sector_cache_[sector_address] = sector;
					return sector;
				}
			}

			return nullptr;
		}
};

std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<Storage::Disk::Disk> &disk) {
	std::vector<File> files;
	CommodoreGCRParser parser;
	parser.drive->set_disk(disk);

	// find any sector whatsoever to establish the current track
	std::shared_ptr<CommodoreGCRParser::Sector> sector;

	// assemble directory
	std::vector<uint8_t> directory;
	uint8_t next_track = 18;
	uint8_t next_sector = 1;
	while(1) {
		sector = parser.get_sector(next_track, next_sector);
		if(!sector) break;
		directory.insert(directory.end(), sector->data.begin(), sector->data.end());
		next_track = sector->data[0];
		next_sector = sector->data[1];

		if(!next_track) break;
	}

	// parse directory
	std::size_t header_pointer = static_cast<std::size_t>(-32);
	while(header_pointer+32+31 < directory.size()) {
		header_pointer += 32;

		File new_file;
		switch(directory[header_pointer + 2] & 7) {
			case 0:				// DEL files
			default: continue;	// Unknown file types

			case 1:	new_file.type = File::DataSequence;			break;
			case 2:	new_file.type = File::RelocatableProgram;	break;	// TODO: need a "don't know about relocatable" program?
			case 3:	new_file.type = File::User;					break;
//			case 4:	new_file.type = File::Relative;				break;	// Can't handle REL files yet
		}

		next_track = directory[header_pointer + 3];
		next_sector = directory[header_pointer + 4];

		new_file.raw_name.reserve(16);
		for(std::size_t c = 0; c < 16; c++) {
			new_file.raw_name.push_back(directory[header_pointer + 5 + c]);
		}
		new_file.name = Storage::Data::Commodore::petscii_from_bytes(&new_file.raw_name[0], 16, false);

		std::size_t number_of_sectors = static_cast<std::size_t>(directory[header_pointer + 0x1e]) + (static_cast<std::size_t>(directory[header_pointer + 0x1f]) << 8);
		new_file.data.reserve((number_of_sectors - 1) * 254 + 252);

		bool is_first_sector = true;
		while(next_track) {
			sector = parser.get_sector(next_track, next_sector);
			if(!sector) break;

			next_track = sector->data[0];
			next_sector = sector->data[1];

			if(is_first_sector) new_file.starting_address = static_cast<uint16_t>(sector->data[2]) | static_cast<uint16_t>(sector->data[3] << 8);
			if(next_track)
				new_file.data.insert(new_file.data.end(), sector->data.begin() + (is_first_sector ? 4 : 2), sector->data.end());
			else
				new_file.data.insert(new_file.data.end(), sector->data.begin() + 2, sector->data.begin() + next_sector);

			is_first_sector = false;
		}

		if(!next_track) files.push_back(new_file);
	}

	return files;
}
<commit_msg>Eliminates local `drive`. They're not local any more.<commit_after>//
//  Disk.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 13/09/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#include "Disk.hpp"
#include "../../../Storage/Disk/Controller/DiskController.hpp"
#include "../../../Storage/Disk/Encodings/CommodoreGCR.hpp"
#include "../../../Storage/Data/Commodore.hpp"

#include <limits>
#include <vector>
#include <array>

using namespace Analyser::Static::Commodore;

class CommodoreGCRParser: public Storage::Disk::Controller {
	public:
		CommodoreGCRParser() : Storage::Disk::Controller(4000000), shift_register_(0), track_(1) {
			emplace_drive(4000000, 300, 2);
			set_drive(1);
			get_drive().set_motor_on(true);
		}

		struct Sector {
			uint8_t sector, track;
			std::array<uint8_t, 256> data;
			bool header_checksum_matched;
			bool data_checksum_matched;
		};

		/*!
			Attempts to read the sector located at @c track and @c sector.

			@returns a sector if one was found; @c nullptr otherwise.
		*/
		std::shared_ptr<Sector> get_sector(uint8_t track, uint8_t sector) {
			int difference = static_cast<int>(track) - static_cast<int>(track_);
			track_ = track;

			if(difference) {
				int direction = difference < 0 ? -1 : 1;
				difference *= direction;

				for(int c = 0; c < difference; c++) {
					get_drive().step(Storage::Disk::HeadPosition(direction));
				}

				unsigned int zone = 3;
				if(track >= 18) zone = 2;
				else if(track >= 25) zone = 1;
				else if(track >= 31) zone = 0;
				set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(zone));
			}

			return get_sector(sector);
		}

		void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk) {
			get_drive().set_disk(disk);
		}

	private:
		unsigned int shift_register_;
		int index_count_;
		int bit_count_;
		uint8_t track_;
		std::shared_ptr<Sector> sector_cache_[65536];

		void process_input_bit(int value) {
			shift_register_ = ((shift_register_ << 1) | static_cast<unsigned int>(value)) & 0x3ff;
			bit_count_++;
		}

		unsigned int proceed_to_next_block(int max_index_count) {
			// find GCR lead-in
			proceed_to_shift_value(0x3ff);
			if(shift_register_ != 0x3ff) return 0xff;

			// find end of lead-in
			while(shift_register_ == 0x3ff && index_count_ < max_index_count) {
				run_for(Cycles(1));
			}

			// continue for a further nine bits
			bit_count_ = 0;
			while(bit_count_ < 9 && index_count_ < max_index_count) {
				run_for(Cycles(1));
			}

			return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
		}

		unsigned int get_next_byte() {
			bit_count_ = 0;
			while(bit_count_ < 10) run_for(Cycles(1));
			return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
		}

		void proceed_to_shift_value(unsigned int shift_value) {
			const int max_index_count = index_count_ + 2;
			while(shift_register_ != shift_value && index_count_ < max_index_count) {
				run_for(Cycles(1));
			}
		}

		void process_index_hole() {
			index_count_++;
		}

		std::shared_ptr<Sector> get_sector(uint8_t sector) {
			uint16_t sector_address = static_cast<uint16_t>((track_ << 8) | sector);
			if(sector_cache_[sector_address]) return sector_cache_[sector_address];

			std::shared_ptr<Sector> first_sector = get_next_sector();
			if(!first_sector) return first_sector;
			if(first_sector->sector == sector) return first_sector;

			while(1) {
				std::shared_ptr<Sector> next_sector = get_next_sector();
				if(next_sector->sector == first_sector->sector) return nullptr;
				if(next_sector->sector == sector) return next_sector;
			}
		}

		std::shared_ptr<Sector> get_next_sector() {
			auto sector = std::make_shared<Sector>();
			const int max_index_count = index_count_ + 2;

			while(index_count_ < max_index_count) {
				// look for a sector header
				while(1) {
					if(proceed_to_next_block(max_index_count) == 0x08) break;
					if(index_count_ >= max_index_count) return nullptr;
				}

				// get sector details, skip if this looks malformed
				uint8_t checksum = static_cast<uint8_t>(get_next_byte());
				sector->sector = static_cast<uint8_t>(get_next_byte());
				sector->track = static_cast<uint8_t>(get_next_byte());
				uint8_t disk_id[2];
				disk_id[0] = static_cast<uint8_t>(get_next_byte());
				disk_id[1] = static_cast<uint8_t>(get_next_byte());
				if(checksum != (sector->sector ^ sector->track ^ disk_id[0] ^ disk_id[1])) continue;

				// look for the following data
				while(1) {
					if(proceed_to_next_block(max_index_count) == 0x07) break;
					if(index_count_ >= max_index_count) return nullptr;
				}

				checksum = 0;
				for(std::size_t c = 0; c < 256; c++) {
					sector->data[c] = static_cast<uint8_t>(get_next_byte());
					checksum ^= sector->data[c];
				}

				if(checksum == get_next_byte()) {
					uint16_t sector_address = static_cast<uint16_t>((sector->track << 8) | sector->sector);
					sector_cache_[sector_address] = sector;
					return sector;
				}
			}

			return nullptr;
		}
};

std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<Storage::Disk::Disk> &disk) {
	std::vector<File> files;
	CommodoreGCRParser parser;
	parser.set_disk(disk);

	// find any sector whatsoever to establish the current track
	std::shared_ptr<CommodoreGCRParser::Sector> sector;

	// assemble directory
	std::vector<uint8_t> directory;
	uint8_t next_track = 18;
	uint8_t next_sector = 1;
	while(1) {
		sector = parser.get_sector(next_track, next_sector);
		if(!sector) break;
		directory.insert(directory.end(), sector->data.begin(), sector->data.end());
		next_track = sector->data[0];
		next_sector = sector->data[1];

		if(!next_track) break;
	}

	// parse directory
	std::size_t header_pointer = static_cast<std::size_t>(-32);
	while(header_pointer+32+31 < directory.size()) {
		header_pointer += 32;

		File new_file;
		switch(directory[header_pointer + 2] & 7) {
			case 0:				// DEL files
			default: continue;	// Unknown file types

			case 1:	new_file.type = File::DataSequence;			break;
			case 2:	new_file.type = File::RelocatableProgram;	break;	// TODO: need a "don't know about relocatable" program?
			case 3:	new_file.type = File::User;					break;
//			case 4:	new_file.type = File::Relative;				break;	// Can't handle REL files yet
		}

		next_track = directory[header_pointer + 3];
		next_sector = directory[header_pointer + 4];

		new_file.raw_name.reserve(16);
		for(std::size_t c = 0; c < 16; c++) {
			new_file.raw_name.push_back(directory[header_pointer + 5 + c]);
		}
		new_file.name = Storage::Data::Commodore::petscii_from_bytes(&new_file.raw_name[0], 16, false);

		std::size_t number_of_sectors = static_cast<std::size_t>(directory[header_pointer + 0x1e]) + (static_cast<std::size_t>(directory[header_pointer + 0x1f]) << 8);
		new_file.data.reserve((number_of_sectors - 1) * 254 + 252);

		bool is_first_sector = true;
		while(next_track) {
			sector = parser.get_sector(next_track, next_sector);
			if(!sector) break;

			next_track = sector->data[0];
			next_sector = sector->data[1];

			if(is_first_sector) new_file.starting_address = static_cast<uint16_t>(sector->data[2]) | static_cast<uint16_t>(sector->data[3] << 8);
			if(next_track)
				new_file.data.insert(new_file.data.end(), sector->data.begin() + (is_first_sector ? 4 : 2), sector->data.end());
			else
				new_file.data.insert(new_file.data.end(), sector->data.begin() + 2, sector->data.begin() + next_sector);

			is_first_sector = false;
		}

		if(!next_track) files.push_back(new_file);
	}

	return files;
}
<|endoftext|>


<commit_before>
// MFCApplication1Dlg.cpp : implementation file
//

#include "stdafx.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// Dialog Data
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// CMFCApplication1Dlg dialog

CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_MONTHCALENDAR1, m_monthCalCtrl);
}

BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()

BOOL CMFCApplication1Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here
	SYSTEMTIME systime;
	::GetSystemTime(&systime);
	SYSTEMTIME sysFromtime;
	SYSTEMTIME sysEndtime;
	sysFromtime = systime;
	sysEndtime = systime;
	sysFromtime.wDay = 1;
	sysFromtime.wMonth = 1;
	sysEndtime.wDay = 31;
	sysEndtime.wMonth = 12;
	m_monthCalCtrl.SetRange(&sysFromtime, &sysEndtime);
	m_monthCalCtrl.SetOriginalColors();
	m_monthCalCtrl.EnableMultiselect(15);
	std::vector<SYSTEMTIME> dates;
	dates.push_back(sysEndtime);
	dates.push_back(sysFromtime);
	m_monthCalCtrl.SetCurSel(&sysEndtime);
	m_monthCalCtrl.SetCurSel(&sysFromtime);
	//m_monthCalCtrl.UnselectAll();
	int nCount = m_monthCalCtrl.GetMonthRange(&sysEndtime, &sysFromtime, GMR_DAYSTATE);
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMFCApplication1Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMFCApplication1Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

<commit_msg>Added test<commit_after>
// MFCApplication1Dlg.cpp : implementation file
//

#include "stdafx.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// Dialog Data
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// CMFCApplication1Dlg dialog

CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_MONTHCALENDAR1, m_monthCalCtrl);
}

BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()

BOOL CMFCApplication1Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here
	SYSTEMTIME systime;
	::GetSystemTime(&systime);
	SYSTEMTIME sysFromtime;
	SYSTEMTIME sysEndtime;
	sysFromtime = systime;
	sysEndtime = systime;
	sysFromtime.wDay = 1;
	sysFromtime.wMonth = 1;
	sysEndtime.wDay = 31;
	sysEndtime.wMonth = 12;
	m_monthCalCtrl.SetRange(&sysFromtime, &sysEndtime);
	m_monthCalCtrl.SetOriginalColors();
	m_monthCalCtrl.EnableMultiselect(15);
	std::vector<SYSTEMTIME> dates;
	dates.push_back(sysEndtime);
	dates.push_back(sysFromtime);
	m_monthCalCtrl.SetCurSel(&sysEndtime);
	m_monthCalCtrl.SetCurSel(&sysFromtime);
	//m_monthCalCtrl.UnselectAll();
	int nCount = m_monthCalCtrl.GetMonthRange(&sysEndtime, &sysFromtime, GMR_DAYSTATE);

	CMultipleMonthCalCtrl button;
	button.Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | DT_CENTER, CRect(5, 5, 55, 19), this, 111);

	button.SetRange(&sysFromtime, &sysEndtime);
	button.SetOriginalColors();
	button.EnableMultiselect(15);
	button.SetCurSel(&sysEndtime);
	button.SetCurSel(&sysFromtime);

	CMultipleMonthCalCtrl * newCtrl = new CMultipleMonthCalCtrl();
	newCtrl->Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | DT_CENTER, CRect(5, 5, 55, 19), this, 111);
	newCtrl->SetRange(&sysFromtime, &sysEndtime);
	newCtrl->SetOriginalColors();
	newCtrl->EnableMultiselect(15);
	newCtrl->SetCurSel(&sysEndtime);
	newCtrl->SetCurSel(&sysFromtime);
	delete newCtrl;

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMFCApplication1Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMFCApplication1Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

<|endoftext|>


<commit_before>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <sauce/sauce.h>

namespace sauce { namespace test {

  struct Chasis {
    virtual const char * name() = 0;
  };

  struct CoupChasis: public Chasis {
    virtual const char * name() { return "coup"; }
  };

  struct TruckChasis: public Chasis {
    virtual const char * name() { return "truck"; }
  };

  struct Engine {
    virtual const char * name() = 0;
  };

  struct HybridEngine: public Engine {
    virtual const char * name() { return "hybrid"; }
  };

  struct DieselEngine: public Engine {
    virtual const char * name() { return "diesel"; }
  };

  struct Vehicle {
    virtual const char * name() = 0;

    virtual Chasis & getChasis() = 0;
    virtual Engine & getEngine() = 0;
  };

  struct Herbie: public Vehicle {
    Chasis & chasis;
    Engine & engine;

    Herbie(Chasis & chasis, Engine & engine):
      chasis(chasis),
      engine(engine) {}

    virtual const char * name() { return "herbie"; }
  };

  // struct CementMixer: public Vehicle {
  //   Chasis * chasis;
  //   Engine * engine;
  //
  //   void setChasis(Chasis & chasis) { this->chasis = &chasis; }
  //   void setEngine(Engine & engine) { this->engine = &engine; }
  //
  //   virtual const char * name() { return "cement mixer"; }
  // };

  class LoveBugModule {
  public:

    template<typename Injector>
    static ::sauce::internal::bindings::New<Injector, Chasis, CoupChasis()> * bindings(Chasis *) {
      return 0;
    }

    template<typename Injector>
    static ::sauce::internal::bindings::Dereference<Injector, Chasis> * bindings(Chasis &) {
      return 0;
    }

    template<typename Injector>
    static ::sauce::internal::bindings::New<Injector, Engine, HybridEngine()> * bindings(Engine *) {
      return 0;
    }

    template<typename Injector>
    static ::sauce::internal::bindings::New<Injector, Vehicle, Herbie(Chasis &, Engine &)> * bindings(Vehicle *) {
      return 0;
    }

  };

  class MockNewDelete {
  public:

    // MOCK_METHOD2(Delete, void (Derp * derp));

  };

  class SauceTest : public ::testing::Test {
  public:

    // ::sauce::Injector<LoveBugModule, MockNewDelete> injector;
    // MockNewDelete & new_delete;
    ::sauce::Injector<LoveBugModule> injector;

    // SauceTest is a friend of Injector
    // SauceTest():
    //   injector(),
    //   new_delete(injector.new_delete) {}

  };

  TEST_F(SauceTest, should_provide_a_dependency) {
    Chasis * chasis = injector.provide<Chasis *>();
    ASSERT_STREQ("coup", chasis->name());
    delete chasis;
  }

  TEST_F(SauceTest, should_dispose_a_dependency) {
    Chasis * chasis = injector.provide<Chasis *>();
    injector.dispose<Chasis *>(chasis);
  }

  TEST_F(SauceTest, should_dereference_addresses_with_dereference_bindings) {
    Chasis & chasis = injector.provide<Chasis &>();
    ASSERT_STREQ("coup", chasis.name());
    injector.dispose<Chasis &>(chasis);
  }

} } // namespace test, namespace sauce
<commit_msg>Use NewDelete mock expectations in the tests.<commit_after>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <sauce/sauce.h>

using ::testing::Return;

namespace sauce { namespace test {

  struct Chasis {
    virtual const char * name() = 0;
  };

  struct CoupChasis: public Chasis {
    virtual const char * name() { return "coup"; }
  };

  struct TruckChasis: public Chasis {
    virtual const char * name() { return "truck"; }
  };

  struct Engine {
    virtual const char * name() = 0;
  };

  struct HybridEngine: public Engine {
    virtual const char * name() { return "hybrid"; }
  };

  struct DieselEngine: public Engine {
    virtual const char * name() { return "diesel"; }
  };

  struct Vehicle {
    virtual const char * name() = 0;

    virtual Chasis & getChasis() = 0;
    virtual Engine & getEngine() = 0;
  };

  struct Herbie: public Vehicle {
    Chasis & chasis;
    Engine & engine;

    Herbie(Chasis & chasis, Engine & engine):
      chasis(chasis),
      engine(engine) {}

    virtual const char * name() { return "herbie"; }
  };

  // struct CementMixer: public Vehicle {
  //   Chasis * chasis;
  //   Engine * engine;
  //
  //   void setChasis(Chasis & chasis) { this->chasis = &chasis; }
  //   void setEngine(Engine & engine) { this->engine = &engine; }
  //
  //   virtual const char * name() { return "cement mixer"; }
  // };

  class LoveBugModule {
  public:

    template<typename Injector>
    static ::sauce::internal::bindings::New<Injector, Chasis, CoupChasis()> * bindings(Chasis *) {
      return 0;
    }

    template<typename Injector>
    static ::sauce::internal::bindings::Dereference<Injector, Chasis> * bindings(Chasis &) {
      return 0;
    }

    template<typename Injector>
    static ::sauce::internal::bindings::New<Injector, Engine, HybridEngine()> * bindings(Engine *) {
      return 0;
    }

    template<typename Injector>
    static ::sauce::internal::bindings::New<Injector, Vehicle, Herbie(Chasis &, Engine &)> * bindings(Vehicle *) {
      return 0;
    }

  };

  // Our mock for the new and delete operations.
  //
  // Gmock is unable to provide a general mock, so we roll one for our fixure
  // types.  Our mocked methods are actually arbitrary non-templated methods,
  // delegated to by template specializations for our types.
  class MockNewDelete {
  public:

    template<class C> C * _new();
    template<class C> void _delete(C *);

    MOCK_METHOD0(new_coup_chasis, CoupChasis * ());
    MOCK_METHOD1(delete_coup_chasis, void (CoupChasis *));

  };

  template<>
  CoupChasis * MockNewDelete::_new<CoupChasis>() {
    return new_coup_chasis();
  }

  template<>
  void MockNewDelete::_delete<CoupChasis>(CoupChasis * chasis) {
    delete_coup_chasis(chasis);
  }

  class SauceTest : public ::testing::Test {
  public:

    ::sauce::Injector<LoveBugModule, MockNewDelete> injector;
    MockNewDelete & new_delete;

    // SauceTest is a friend of Injector
    SauceTest():
      injector(),
      new_delete(injector.new_delete) {}

  };

  TEST_F(SauceTest, should_provide_a_dependency) {
    CoupChasis chasis;
    EXPECT_CALL(new_delete, new_coup_chasis()).WillOnce(Return(&chasis));
    Chasis * actual = injector.provide<Chasis *>();
    ASSERT_EQ(&chasis, actual);
  }

  TEST_F(SauceTest, should_dispose_a_dependency) {
    CoupChasis chasis;
    // EXPECT_CALL(new_delete, delete_coup_chasis(&chasis));
    injector.dispose<Chasis *>(&chasis);
  }

  TEST_F(SauceTest, should_dereference_addresses_with_dereference_bindings) {
    CoupChasis chasis;
    EXPECT_CALL(new_delete, new_coup_chasis()).WillOnce(Return(&chasis));
    // EXPECT_CALL(new_delete, delete_coup_chasis(&chasis));

    Chasis & actual = injector.provide<Chasis &>();
    ASSERT_EQ(&chasis, &actual);
    injector.dispose<Chasis &>(chasis);
  }

} } // namespace test, namespace sauce
<|endoftext|>