1 /*
2 This file is part of GNU APL, a free implementation of the
3 ISO/IEC Standard 13751, "Programming Language APL, Extended"
4
5 Copyright (C) 2008-2015 Dr. Jürgen Sauermann
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "Avec.hh"
22 #include "Common.hh"
23 #include "DiffOut.hh"
24 #include "InputFile.hh"
25 #include "IO_Files.hh"
26 #include "Output.hh"
27 #include "Performance.hh"
28 #include "UTF8_string.hh"
29
30 //-----------------------------------------------------------------------------
31 int
overflow(int c)32 DiffOut::overflow(int c)
33 {
34 PERFORMANCE_START(cout_perf)
35 Output::set_color_mode(errout ? Output::COLM_UERROR : Output::COLM_OUTPUT);
36
37 // expand LF to CRLF if desired
38 //
39 if (expand_LF && c == '\n') cout << "\r";
40
41 cout << char(c);
42
43 if (!InputFile::is_validating())
44 {
45 PERFORMANCE_END(fs_COUT_B, cout_perf, 1)
46 return 0;
47 }
48
49 if (c != '\n') // not end of line
50 {
51 aplout += c;
52 PERFORMANCE_END(fs_COUT_B, cout_perf, 1)
53 return 0;
54 }
55
56 // complete line received
57 //
58 ofstream & rep = IO_Files::get_current_testreport();
59 Assert(rep.is_open());
60
61 const char * apl = aplout.c_str();
62 UTF8_string ref;
63 bool eof = false;
64 IO_Files::read_file_line(ref, eof);
65 if (eof) // nothing in current_testfile
66 {
67 rep << "extra: " << apl << endl;
68 }
69 else if (different(utf8P(apl), utf8P(ref.c_str())))
70 {
71 IO_Files::diff_error();
72 rep << "apl: ⋅⋅⋅" << apl << "⋅⋅⋅" << endl
73 << "ref: ⋅⋅⋅" << ref.c_str() << "⋅⋅⋅" << endl;
74 }
75 else // same
76 {
77 rep << "== " << apl << endl;
78 }
79
80 aplout.clear();
81 PERFORMANCE_END(fs_COUT_B, cout_perf, 1)
82 return 0;
83 }
84 //-----------------------------------------------------------------------------
85 bool
different(const UTF8 * apl,const UTF8 * ref)86 DiffOut::different(const UTF8 * apl, const UTF8 * ref)
87 {
88 for (;;)
89 {
90 int len_apl, len_ref;
91
92 const Unicode a = UTF8_string::toUni(apl, len_apl, true);
93 const Unicode r = UTF8_string::toUni(ref, len_ref, true);
94 apl += len_apl;
95 ref += len_ref;
96
97 if (a == r) // same char
98 {
99 if (a == 0) return false; // not different
100 continue;
101 }
102
103 // different chars: try special matches (⁰, ¹, ², or ⁿ)...
104
105 if (r == UNI_PAD_U0) // ⁰: match one or more digits
106 {
107 if (!Avec::is_digit(a)) return true; // different
108
109 // skip trailing digits
110 while (Avec::is_digit(Unicode(*apl))) ++apl;
111 continue;
112 }
113
114 if (r == UNI_PAD_U1) // ¹: match zero or more spaces
115 {
116 if (a != UNI_ASCII_SPACE) return true; // different
117
118 // skip trailing digits
119 while (*apl == ' ') ++apl;
120 continue;
121 }
122
123 if (r == UNI_PAD_U2) // ²: match floating point number
124 {
125 if (!Avec::is_digit(a) &&
126 a != UNI_OVERBAR &&
127 a != UNI_ASCII_E &&
128 a != UNI_ASCII_J &&
129 a != UNI_ASCII_FULLSTOP) return true; // different
130
131 // skip trailing digits
132 //
133 for (;;)
134 {
135 if (Avec::is_digit(Unicode(*apl)) ||
136 *apl == UNI_ASCII_E ||
137 *apl == UNI_ASCII_J ||
138 *apl == UNI_ASCII_FULLSTOP) ++apl;
139 else
140 {
141 int len;
142 if (UTF8_string::toUni(apl, len, true) == UNI_OVERBAR)
143 {
144 apl += len;
145 continue;
146 }
147 else break;
148 }
149 }
150
151 continue;
152 }
153
154 if (r == UNI_PAD_U3) // ³: match anything
155 return false; // not different
156
157 if (r == UNI_PAD_U4) // ⁴: match optional ¯
158 {
159 if (a != UNI_OVERBAR) apl -= len_apl; // restore apl
160 continue;
161 }
162
163 if (r == UNI_PAD_U5) // ⁵: match + or -
164 {
165 if (a != '+' && a != '-') return true; // different
166 continue;
167 }
168
169 if (r == UNI_PAD_U6) // ⁶: match 28 ⎕CR 42
170 {
171 #ifdef RATIONAL_NUMBERS_WANTED
172 if (a != '1') return true; // different
173 #else
174 if (a != '0') return true; // different
175 #endif
176 continue;
177 }
178 if (r == UNI_PAD_Un) // ⁿ: optional unit multiplier
179 {
180 // ⁿ shall match an optional unit multiplier, ie.
181 // m, n, u, or μ
182 //
183 if (a == 'm') continue;
184 if (a == 'n') continue;
185 if (a == 'u') continue;
186 if (a == UNI_MUE) continue;
187
188 // no unit matches as well
189 apl -= len_apl;
190 continue;
191 }
192
193 return true; // different
194 }
195
196 return false; // not different
197 }
198 //-----------------------------------------------------------------------------
199