B - Etc

This appendix contains files that are required to build the examples in Volume 2.

//: :require.h

// Test for error conditions in programs.

#ifndef REQUIRE_H

#define REQUIRE_H

#include <cstdio>

#include <cstdlib>

#include <fstream>

 

inline void require(bool requirement,

 const char* msg = "Requirement failed") {

 // Local "using namespace std" for old compilers:

 using namespace std;

 if(!requirement) {

   fputs(msg, stderr);

   fputs("\n", stderr);

   exit(EXIT_FAILURE);

 }

}

 

inline void requireArgs(int argc, int args,

 const char* msg = "Must use %d arguments") {

 using namespace std;

  if(argc != args + 1) {

   fprintf(stderr, msg, args);

   fputs("\n", stderr);

   exit(EXIT_FAILURE);

 }

}

 

inline void requireMinArgs(int argc, int minArgs,

 const char* msg = "Must use at least %d arguments") {

 using namespace std;

 if(argc < minArgs + 1) {

   fprintf(stderr, msg, minArgs);

   fputs("\n", stderr);

   exit(EXIT_FAILURE);

 }

}

 

inline void assure(std::ifstream& in,

 const char* filename = "") {

 using namespace std;

 if(!in) {

   fprintf(stderr, "Could not open file %s\n", filename);

   exit(EXIT_FAILURE);

 }

}

 

inline void assure(std::ofstream& in,

 const char* filename = "") {

 using namespace std;

 if(!in) {

   fprintf(stderr, "Could not open file %s\n", filename);

   exit(EXIT_FAILURE);

 }

}

 

inline void assure(std::fstream& in,

 const char* filename = "") {

 using namespace std;

 if(!in) {

   fprintf(stderr, "Could not open file %s\n", filename);

   exit(EXIT_FAILURE);

 }

}

#endif // REQUIRE_H ///:~

 

//: C0B:Dummy.cpp

// To give the makefile at least

// one target for this directory.

int main() {} ///:~

 

The Date class files:

//: C02:Date.h

#ifndef DATE_H

#define DATE_H

#include <string>

#include <stdexcept>

#include <iosfwd>

 

class Date {

 int year, month, day;

 int compare(const Date&) const;

 static int daysInPrevMonth(int year, int mon);

public:

 // A class for date calculations

 struct Duration {

   int years, months, days;

   Duration(int y, int m, int d)

   : years(y), months(m) ,days(d) {}

 };

 // An exception class

 struct DateError : public std::logic_error {

   DateError(const std::string& msg = "")

: std::logic_error(msg) {}

 };

 Date();

 Date(int, int, int) throw(DateError);

 Date(const std::string&) throw(DateError);

 int getYear() const;

 int getMonth() const;

 int getDay() const;

 std::string toString() const;

 friend Duration duration(const Date&, const Date&);

 friend bool operator<(const Date&, const Date&);

 friend bool operator<=(const Date&, const Date&);

 friend bool operator>(const Date&, const Date&);

 friend bool operator>=(const Date&, const Date&);

 friend bool operator==(const Date&, const Date&);

 friend bool operator!=(const Date&, const Date&);

 friend std::ostream& operator<<(std::ostream&,

                                 const Date&);

 friend std::istream& operator>>(std::istream&, Date&);

};

#endif // DATE_H ///:~

 

//: C02:Date.cpp {O}

#include "Date.h"

#include <iostream>

#include <sstream>

#include <cstdlib>

#include <string>

#include <algorithm> // For swap()

#include <ctime>

#include <cassert>

#include <iomanip>

using namespace std;

 

namespace {

 const int daysInMonth[][13] = {

   { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },

   { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }

 };

 inline bool isleap(int y) {

   return y%4 == 0 && y%100 != 0 || y%400 == 0;

 }

}

 

Date::Date() {

  // Get current date

 time_t tval = time(0);

 struct tm *now = localtime(&tval);

 year = now->tm_year + 1900;

 month = now->tm_mon + 1;

 day = now->tm_mday;

}

 

Date::Date(int yr,int mon,int dy) throw(Date::DateError) {

 if(!(1 <= mon && mon <= 12))

   throw DateError("Bad month in Date ctor");

 if(!(1 <= dy && dy <= daysInMonth[isleap(year)][mon]))

   throw DateError("Bad day in Date ctor");

 year = yr;

 month = mon;

 day = dy;

}

 

Date::Date(const std::string& s) throw(Date::DateError) {

 // Assume YYYYMMDD format

 if(!(s.size() == 8))

   throw DateError("Bad string in Date ctor");

 for(int n = 8; --n >= 0;)

   if(!isdigit(s[n]))

     throw DateError("Bad string in Date ctor");

 string buf = s.substr(0, 4);

 year = atoi(buf.c_str());

 buf = s.substr(4, 2);

 month = atoi(buf.c_str());

 buf = s.substr(6, 2);

 day = atoi(buf.c_str());

 if(!(1 <= month && month <= 12))

   throw DateError("Bad month in Date ctor");

if(!(1 <= day && day <=

 daysInMonth[isleap(year)][month]))

   throw DateError("Bad day in Date ctor");

}

 

int Date::getYear() const { return year; }

 

int Date::getMonth() const { return month; }

 

int Date::getDay() const { return day; }

 

string Date::toString() const {

 ostringstream os;

 os.fill('0');

 os << setw(4) << year

    << setw(2) << month

    << setw(2) << day;

 return os.str();

}

 

int Date::compare(const Date& d2) const {

 int result = year - d2.year;

 if(result == 0) {

   result = month - d2.month;

   if(result == 0)

     result = day - d2.day;

 }

 return result;

}

 

int Date::daysInPrevMonth(int year, int month) {

 if(month == 1) {

   --year;

   month = 12;

 }

 else

   --month;

 return daysInMonth[isleap(year)][month];

}

 

bool operator<(const Date& d1, const Date& d2) {

  return d1.compare(d2) < 0;

}

bool operator<=(const Date& d1, const Date& d2) {

  return d1 < d2 || d1 == d2;

}

bool operator>(const Date& d1, const Date& d2) {

  return !(d1 < d2) && !(d1 == d2);

}

bool operator>=(const Date& d1, const Date& d2) {

  return !(d1 < d2);

}

bool operator==(const Date& d1, const Date& d2) {

  return d1.compare(d2) == 0;

}

bool operator!=(const Date& d1, const Date& d2) {

  return !(d1 == d2);

}

 

Date::Duration

duration(const Date& date1, const Date& date2) {

 int y1 = date1.year;

 int y2 = date2.year;

 int m1 = date1.month;

 int m2 = date2.month;

 int d1 = date1.day;

 int d2 = date2.day;

 

 // Compute the compare

 int order = date1.compare(date2);

 if(order == 0)

   return Date::Duration(0,0,0);

 else if(order > 0) {

   // Make date1 precede date2 locally

   using std::swap;

   swap(y1, y2);

   swap(m1, m2);

   swap(d1, d2);

 }

 

 int years = y2 - y1;

 int months = m2 - m1;

 int days = d2 - d1;

 assert(years > 0 ||

    years == 0 && months > 0 ||

    years == 0 && months == 0 && days > 0);

 

 // Do the obvious corrections (must adjust days

 // before months!) - This is a loop in case the

 // previous month is February, and days < -28.

 int lastMonth = m2;

 int lastYear = y2;

 while(days < 0) {

   // Borrow from month

   assert(months > 0);

   days += Date::daysInPrevMonth(

     lastYear, lastMonth--);

   --months;

 }

 

 if(months < 0) {

   // Borrow from year

   assert(years > 0);

   months += 12;

   --years;

 }

 return Date::Duration(years, months, days);

}

 

ostream& operator<<(ostream& os, const Date& d) {

 char fillc = os.fill('0');

 os << setw(2) << d.getMonth() << ‘-‘

    << setw(2) << d.getDay() << ‘-‘

    << setw(4) << setfill(fillc) << d.getYear();

 return os;

}

 

istream& operator>>(istream& is, Date& d) {

 is >> d.month;

 char dash;

 is >> dash;

 if(dash != '-')

   is.setstate(ios::failbit);

 is >> d.day;

 is >> dash;

 if(dash != '-')

   is.setstate(ios::failbit);

 is >> d.year;

 return is;

} ///:~

 

The file test.txt used in Chapter 6:

//: C06:Test.txt

f a f d A  G f d F a A F h f A d f f a a

///:~