\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$\.{}$\par \B\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