summaryrefslogtreecommitdiff
path: root/web/c_cpp/cwebx/compare.tex
blob: 8d8c03f4907ad6f95aa8986e47d940544948c8a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
\input cwebxmac

\N0 1.  Comparing text files.
This is an entirely trivial program, that tests whether two text files are
equal, and if not so, points out the first point of difference.

\Y\B\h$\.{<stdio.h>}$\par
\B\h$\.{<stdlib.h>}$\par
\Y\B$\&{typedef}~\&{char}~\&{bool};$\par
\fi

\M2. The outline of the program is simple. We read characters from both input
files into $ c_1$ and~$ c_2$ until the comparison is complete. Line and column
counts are maintained in $\\{line}$ and~$\\{col}$.

\Y\B\D$\\{left\_margin}$\5
$\T{1}$\C{ leftmost column number; change to 0 if you prefer }\par
\Y\B$\X5:Functions\X$\7
\&{int} $\\{main}$\5
$(\1\1\1\&{int}~ n,\31~\&{char}~\m*\m*\\{arg}\2\2\2)$\6
$\a\{\1\&{FILE}~\m* f_1,\31~\m* f_2;$\C{ the two input files }\6
$\&{int}~ c_1,\31~ c_2,\31~\\{col}\K\\{left\_margin};$\6
$\&{long}~\\{line}\K\T{1};$\7
$\X6:Open the files $ f_1$ and~$ f_2$, taking their names from the command line
or from the terminal; in case of an error for which no recovery is possible,
call $\\{exit}(\T{1})$\X$\6
$\X3:Search for first difference, leaving $ c_1\I c_2$ if and only if a
difference was found\X$\6
$\X4:Report the outcome of the comparison\X$\6
$\&{return}~\T{0};$\C{ successful completion }\2\6
$\}$\par
\fi

\M3. The heart of the program is this simple loop.  When we reach the end of
one of the files, the files match if and only if the other file has also
reached its end. For this reason the test $ c_1\E c_2$, which requires
characters to be read from both files, must precede the test for file end;
when only one file ends, it is the former test which breaks the loop.

\Y\B\4$\X3:Search for first difference, leaving $ c_1\I c_2$ if and only if a
difference was found\X\EQ{}$\6
\&{while}~$(( c_1\K\\{getc}( f_1))\E( c_2\K\\{getc}( f_2))\W c_1\I\.{EOF})\1$\6
\&{if}~$( c_1\E\.{'\\n'})\1$\5
$\{\1$\5
$\PP\\{line};$\5
$\\{col}\K\\{left\_margin};\2$\5
$\}$\5
\2\&{else}\1\5
$\PP\\{col};\2$\2\par
\U 2.\fi

\M4. When the first difference occurs at the end of one of the files, or at the
end of a line, we give a message indicating this fact.

\Y\B\4$\X4:Report the outcome of the comparison\X\EQ{}$\6
\&{if}~$( c_1\E c_2)\1$\5
$\\{printf}(\.{"Files\ match.\\n"});\2$\6
\&{else}\6
$\a\{\1\\{printf}(\.{"Files\ differ.\\n"});$\6
\&{if}~$( c_1\E\.{EOF}\V c_2\E\.{EOF})$\1\6
$\{\1$\5
$\\{the\_file}( c_1\E\.{EOF});$\5
$\\{printf}(\.{"is\ contained\ in\ the\)\ other\ as\ initial\ seg\)ment.\\n"});%
\2$\5
$\}\2$\6
\&{else}~\&{if}~$( c_1\E\.{'\\n'}\V c_2\E\.{'\\n'})$\1\6
$\{\1$\5
$\\{the\_file}( c_1\E\.{'\\n'});$\5
$\\{printf}(\.{"has\ a\ shorter\ line\ \)number\ \%ld\ than\ the\ o\)ther.%
\\n"},\31\\{line});\2$\5
$\}\2$\6
\&{else}\1\5
$\\{printf}(\.{"First\ difference\ at\)\ line\ \%ld,\ column\ \%d.\)\\n"},\31%
\\{line},\31\\{col});\2$\2\6
$\}$\par
\U 2.\fi

\M5. The function $\\{the\_file}$ starts a sentence about the first or second
file,
depending on its boolean argument.

\Y\B\4$\X5:Functions\X\EQ{}$\6
\&{void} $\\{the\_file}$\5
$(\1\1\1\&{bool}~\\{is\_first}\2\2\2)$\5
$\{\1$\5
$\\{printf}(\.{"The\ \%s\ file\ "},\31\\{is\_first}\?\.{"first"}:\.{"second"});%
\2$\5
$\}$\par
\A 7.
\U 2.\fi

\M6. There can be be zero, one or two command line arguments. If there are
none,
the user is prompted to supply them, and if there are two these are taken as
the file names, prompting the user only in case a file could not be opened.
In case just one argument is present, the first file is assumed to be the
standard input, which does not have to be opened; in this case however we
will not read a file name from terminal in case the second file cannot be
opened.

\Y\B\D$\\{read\_mode}$\5
$\.{"r"}$\par
\Y\B\4$\X6:Open the files $ f_1$ and~$ f_2$, taking their names from the
command line or from the terminal; in case of an error for which no recovery is
possible, call $\\{exit}(\T{1})$\X\EQ{}$\6
$\MM n;$\5
$\PP\\{arg};$\C{ ignore ``argument'' 0, which is the program name }\6
\&{if}~$( n\E\T{0})$\1\6
$\{\1$\5
$\\{open\_file}(\m\AND f_1,\31\.{"First\ file\ to\ compa\)re"},\31\NULL);$\5
$\\{open\_file}(\m\AND f_2,\31\.{"Second\ file\ to\ comp\)are"},\31\NULL);\2$\5
$\}\2$\6
\&{else}~\&{if}~$( n\E\T{1})$\6
$\a\{\1 f_1\K\\{stdin};$\6
\&{if}~$(( f_2\K\\{fopen}(\m*\\{arg},\31\\{read\_mode}))\E\NULL)\1$\5
$\{\1$\5
$\\{printf}(\.{"Could\ not\ open\ file\)\ \%s.\\n"},\31\m*\\{arg});$\5
$\\{exit}(\T{1});\2$\5
$\}\2$\2\6
$\}$\6
\&{else}~\&{if}~$( n\E\T{2})$\6
$\a\{\1\\{open\_file}(\m\AND f_1,\31\.{"Give\ another\ first\ \)file"},\31\m*%
\\{arg}\PP);$\5
$\\{open\_file}(\m\AND f_2,\31\.{"Give\ another\ second\)\ file"},\31\m*%
\\{arg});\2$\6
$\}$\6
\&{else}\1\5
$\{\1$\5
$\\{printf}(\.{"No\ more\ than\ two\ co\)mmand\ line\ arguments\ \)are\
allowed.\\n"});$\5
$\\{exit}(\T{1});\2$\5
$\}\2$\par
\U 2.\fi

\M7. The function $\\{open\_file}$ will try to open the file $\\{name}$ for
reading, and
if this fails it will prompt for another file name until it has success. If
called with $\\{name}\E\NULL$, the function starts with prompting right away.

\Y\B\4$\X5:Functions\X\PE{}$\6
\&{void} $\\{open\_file}$\5
$(\1\1\1\&{FILE}~\m*\m* f,\31~\&{char}~\m*\\{prompt},\31~\&{char}~\m*\\{name}\2%
\2\2)$\6
$\a\{\1\&{char}~\\{buf}[\T{80}];$\7
\&{if}~$(\\{name}\E\NULL\V(\m* f\K\\{fopen}(\\{name},\31\\{read\_mode}))\E%
\NULL)\1$\6
\&{do}\1\5
$\{\1$\5
$\\{printf}(\.{"\%s:\ "},\31\\{prompt});$\5
$\\{fflush}(\\{stdout});$\5
$\\{scanf}(\.{"\%79s"},\31\\{buf});\2$\5
$\}$\2\6
\&{while}~$((\m* f\K\\{fopen}(\\{buf},\31\\{read\_mode}))\E\NULL);$\2\2\6
$\}$\par
\fi

\N0 8.  Index.
\fi


\inx
\@m\\{arg}, \[2], 6.
\@h\&{bool}, \[1], 5.
\@m\\{buf}, \[7].
\@m\\{col}, \[2], 3, 4.
\@m c_1, \[2], 3, 4.
\@m c_2, \[2], 3, 4.
\@m\.{EOF}, 3, 4.
\@m\\{exit}, 6.
\@m f, \[7].
\@m\\{fflush}, 7.
\@m\\{fopen}, 6, 7.
\@m f_1, \[2], 3, 6.
\@m f_2, \[2], 3, 6.
\@m\\{getc}, 3.
\@m\\{is\_first}, \[5].
\@m\\{left\_margin}, \[2], 3.
\@m\\{line}, \[2], 3, 4.
\@m\\{main}, \[2].
\@m n, \[2].
\@m\\{name}, \[7].
\@m\\{open\_file}, 6, \[7].
\@m\\{printf}, 4, 5, 6, 7.
\@m\\{prompt}, \[7].
\@m\\{read\_mode}, \[6], 7.
\@m\\{scanf}, 7.
\@m\\{stdin}, 6.
\@m\\{stdout}, 7.
\@m\\{the\_file}, 4, \[5].
\fin
\@$\X5, 7:Functions\X$
\U 2.
\@$\X6:Open the files $ f_1$ and~$ f_2$, taking their names from the command
line or from the terminal; in case of an error for which no recovery is
possible, call $\\{exit}(\T{1})$\X$
\U 2.
\@$\X4:Report the outcome of the comparison\X$
\U 2.
\@$\X3:Search for first difference, leaving $ c_1\I c_2$ if and only if a
difference was found\X$
\U 2.
\con