5. B: Etc▲
This appendix contains files that are required to build the examples in Volume 2.
Sélectionnez
//: :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 ///:~
Sélectionnez
//: C0B:Dummy.cpp
// To give the makefile at least
// one target for this directory.
int
main() {}
///
:~
The Date class files:
Sélectionnez
//: 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 ///:~
Sélectionnez
//: 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
&&
y0 !=
0
||
y@0
==
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:
Sélectionnez
//: C06:Test.txt
f a f d A G f d F a A F h f A d f f a a
///
:~