Line data Source code
1 : /* Copyright 1989-2020 Free Software Foundation, Inc.
2 : 2021-2025 G. Branden Robinson
3 :
4 : Written by James Clark (jjc@jclark.com)
5 :
6 : This file is part of groff, the GNU roff typesetting system.
7 :
8 : groff is free software; you can redistribute it and/or modify it under
9 : the terms of the GNU General Public License as published by the Free
10 : Software Foundation, either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 : for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include <config.h>
23 : #endif
24 :
25 : #include <stdckdint.h>
26 :
27 : #include "troff.h" // units
28 : #include "hvunits.h" // hunits, vunits
29 : #include "mtsm.h" // state_set
30 : #include "env.h" // curenv
31 : #include "token.h" // tok
32 : #include "div.h" // curdiv
33 :
34 : const vunits V0; // zero in vertical units
35 : const hunits H0; // zero in horizontal units
36 :
37 : units hresolution = 1;
38 : units vresolution = 1;
39 : units units_per_inch;
40 : int sizescale; // subdivisions per point
41 :
42 : static bool is_valid_expression(units *u, int scaling_unit,
43 : bool is_parenthesized,
44 : bool is_mandatory = false);
45 : static bool is_valid_expression_start();
46 :
47 446546 : bool read_vunits(vunits *res, unsigned char si)
48 : {
49 446546 : if (!is_valid_expression_start())
50 0 : return false;
51 : units x;
52 446546 : if (is_valid_expression(&x, si, false /* is_parenthesized */)) {
53 446546 : *res = vunits(x);
54 446546 : return true;
55 : }
56 : else
57 0 : return false;
58 : }
59 :
60 298847 : bool read_hunits(hunits *res, unsigned char si)
61 : {
62 298847 : if (!is_valid_expression_start())
63 0 : return false;
64 : units x;
65 298847 : if (is_valid_expression(&x, si, false /* is_parenthesized */)) {
66 298847 : *res = hunits(x);
67 298847 : return true;
68 : }
69 : else
70 0 : return false;
71 : }
72 :
73 2856012 : bool read_measurement(units *res, unsigned char si, bool is_mandatory)
74 : {
75 2856012 : if (!is_valid_expression_start())
76 0 : return false;
77 : units x;
78 2856012 : if (is_valid_expression(&x, si, false /* is_parenthesized */,
79 : is_mandatory)) {
80 2855749 : *res = x;
81 2855749 : return true;
82 : }
83 : else
84 263 : return false;
85 : }
86 :
87 564336 : bool read_integer(int *res)
88 : {
89 564336 : if (!is_valid_expression_start())
90 0 : return false;
91 : units x;
92 564336 : if (is_valid_expression(&x, 0 /* dimensionless */,
93 : false /* is_parenthesized */)) {
94 564336 : *res = x;
95 564336 : return true;
96 : }
97 : else
98 0 : return false;
99 : }
100 :
101 : enum incr_number_result { INVALID, ASSIGN, INCREMENT, DECREMENT };
102 :
103 : static incr_number_result get_incr_number(units *res, unsigned char);
104 :
105 97764 : bool read_vunits(vunits *res, unsigned char si, vunits prev_value)
106 : {
107 : units v;
108 : // Use a primitive temporary because having the ckd macros store to
109 : // &(res->n) requires `friend` access and produces wrong results.
110 : int i;
111 97764 : switch (get_incr_number(&v, si)) {
112 1 : case INVALID:
113 1 : return false;
114 97408 : case ASSIGN:
115 97408 : *res = v;
116 97408 : break;
117 168 : case INCREMENT:
118 168 : if (ckd_add(&i, prev_value.to_units(), v))
119 0 : warning(WARN_RANGE, "integer incrementation saturated");
120 168 : *res = i;
121 168 : break;
122 187 : case DECREMENT:
123 187 : if (ckd_sub(&i, prev_value.to_units(), v))
124 0 : warning(WARN_RANGE, "integer decrementation saturated");
125 187 : *res = i;
126 187 : break;
127 0 : default:
128 0 : assert(0 == "unhandled case in read_vunits()");
129 : }
130 97763 : return true;
131 : }
132 :
133 258705 : bool read_hunits(hunits *res, unsigned char si, hunits prev_value)
134 : {
135 : units h;
136 : // Use a primitive temporary because having the ckd macros store to
137 : // &(res->n) requires `friend` access and produces wrong results.
138 : int i;
139 258705 : switch (get_incr_number(&h, si)) {
140 0 : case INVALID:
141 0 : return false;
142 209503 : case ASSIGN:
143 209503 : *res = h;
144 209503 : break;
145 36284 : case INCREMENT:
146 36284 : if (ckd_add(&i, prev_value.to_units(), h))
147 0 : warning(WARN_RANGE, "integer incrementation saturated");
148 36284 : *res = i;
149 36284 : break;
150 12918 : case DECREMENT:
151 12918 : if (ckd_sub(&i, prev_value.to_units(), h))
152 0 : warning(WARN_RANGE, "integer decrementation saturated");
153 12918 : *res = i;
154 12918 : break;
155 0 : default:
156 0 : assert(0 == "unhandled case in read_hunits()");
157 : }
158 258705 : return true;
159 : }
160 :
161 : // TODO: Default `prev_value` to 0.
162 2349779 : bool read_measurement(units *res, unsigned char si, units prev_value)
163 : {
164 : units u;
165 2349779 : switch (get_incr_number(&u, si)) {
166 0 : case INVALID:
167 0 : return false;
168 2093684 : case ASSIGN:
169 2093684 : *res = u;
170 2093684 : break;
171 231391 : case INCREMENT:
172 231391 : if (ckd_add(res, prev_value, u))
173 1 : warning(WARN_RANGE, "integer incrementation saturated");
174 231391 : break;
175 24704 : case DECREMENT:
176 24704 : if (ckd_sub(res, prev_value, u))
177 0 : warning(WARN_RANGE, "integer decrementation saturated");
178 24704 : break;
179 0 : default:
180 0 : assert(0 == "unhandled case in read_measurement()");
181 : }
182 2349779 : return true;
183 : }
184 :
185 233 : bool read_integer(int *res, int prev_value)
186 : {
187 : units i;
188 233 : switch (get_incr_number(&i, 0)) {
189 0 : case INVALID:
190 0 : return false;
191 233 : case ASSIGN:
192 233 : *res = i;
193 233 : break;
194 0 : case INCREMENT:
195 0 : if (ckd_add(res, prev_value, i))
196 0 : warning(WARN_RANGE, "integer incrementation saturated");
197 0 : break;
198 0 : case DECREMENT:
199 0 : if (ckd_sub(res, prev_value, i))
200 0 : warning(WARN_RANGE, "integer decrementation saturated");
201 0 : break;
202 0 : default:
203 0 : assert(0 == "unhandled case in read_integer()");
204 : }
205 233 : return true;
206 : }
207 :
208 :
209 2706481 : static incr_number_result get_incr_number(units *res, unsigned char si)
210 : {
211 2706481 : if (!is_valid_expression_start())
212 0 : return INVALID;
213 2706481 : incr_number_result result = ASSIGN;
214 2706481 : if (tok.ch() == int('+')) { // TODO: grochar
215 267843 : tok.next();
216 267843 : result = INCREMENT;
217 : }
218 2438638 : else if (tok.ch() == int('-')) { // TODO: grochar
219 37809 : tok.next();
220 37809 : result = DECREMENT;
221 : }
222 2706481 : if (is_valid_expression(res, si, false /* is_parenthesized */))
223 2706480 : return result;
224 : else
225 1 : return INVALID;
226 : }
227 :
228 6872222 : static bool is_valid_expression_start()
229 : {
230 6872222 : tok.skip_spaces();
231 6872222 : if (tok.is_newline()) {
232 0 : warning(WARN_MISSING, "numeric expression missing");
233 0 : return false;
234 : }
235 6872222 : return true;
236 : }
237 :
238 : enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
239 :
240 : static const char valid_scaling_units[] = "icfPmnpuvMsz";
241 :
242 : static bool is_valid_term(units *u, int scaling_unit,
243 : bool is_parenthesized, bool is_mandatory);
244 :
245 9281822 : static bool is_valid_expression(units *u, int scaling_unit,
246 : bool is_parenthesized,
247 : bool is_mandatory)
248 : {
249 9281822 : int result = is_valid_term(u, scaling_unit, is_parenthesized,
250 9281822 : is_mandatory);
251 12622199 : while (result) {
252 12621935 : if (is_parenthesized)
253 5377620 : tok.skip_spaces();
254 12621935 : int op = tok.ch();// safely compares to char literals; TODO: grochar
255 12621935 : switch (op) {
256 2057543 : case int('+'): // TODO: grochar
257 : case int('-'): // TODO: grochar
258 : case int('/'): // TODO: grochar
259 : case int('*'): // TODO: grochar
260 : case int('%'): // TODO: grochar
261 : case int(':'): // TODO: grochar
262 : case int('&'): // TODO: grochar
263 2057543 : tok.next();
264 2057543 : break;
265 436445 : case int('>'): // TODO: grochar
266 436445 : tok.next();
267 436445 : if (tok.ch() == int('=')) { // TODO: grochar
268 130125 : tok.next();
269 130125 : op = OP_GEQ;
270 : }
271 306320 : else if (tok.ch() == int('?')) { // TODO: grochar
272 158803 : tok.next();
273 158803 : op = OP_MAX;
274 : }
275 436445 : break;
276 623178 : case int('<'): // TODO: grochar
277 623178 : tok.next();
278 623178 : if (tok.ch() == int('=')) { // TODO: grochar
279 277180 : tok.next();
280 277180 : op = OP_LEQ;
281 : }
282 345998 : else if (tok.ch() == int('?')) { // TODO: grochar
283 57988 : tok.next();
284 57988 : op = OP_MIN;
285 : }
286 623178 : break;
287 223221 : case int('='): // TODO: grochar
288 223221 : tok.next();
289 223221 : if (tok.ch() == int('=')) // TODO: grochar
290 76684 : tok.next();
291 223221 : break;
292 9281548 : default:
293 9281558 : return result;
294 : }
295 : units u2;
296 3340387 : if (!is_valid_term(&u2, scaling_unit, is_parenthesized,
297 : is_mandatory))
298 10 : return false;
299 3340377 : switch (op) {
300 288009 : case int('<'): // TODO: grochar
301 288009 : *u = *u < u2;
302 288009 : break;
303 147516 : case int('>'): // TODO: grochar
304 147516 : *u = *u > u2;
305 147516 : break;
306 277180 : case OP_LEQ:
307 277180 : *u = *u <= u2;
308 277180 : break;
309 130125 : case OP_GEQ:
310 130125 : *u = *u >= u2;
311 130125 : break;
312 57988 : case OP_MIN:
313 57988 : if (*u > u2)
314 184 : *u = u2;
315 57988 : break;
316 158803 : case OP_MAX:
317 158803 : if (*u < u2)
318 44924 : *u = u2;
319 158803 : break;
320 223220 : case int('='): // TODO: grochar
321 223220 : *u = (*u == u2);
322 223220 : break;
323 57299 : case int('&'): // TODO: grochar
324 57299 : *u = (*u > 0) && (u2 > 0);
325 57299 : break;
326 8235 : case int(':'): // TODO: grochar
327 8235 : *u = (*u > 0) || (u2 > 0);
328 8235 : break;
329 592344 : case int('+'): // TODO: grochar
330 592344 : if (ckd_add(u, *u, u2)) {
331 0 : warning(WARN_RANGE, "integer addition saturated");
332 0 : return false;
333 : }
334 592344 : break;
335 633135 : case int('-'): // TODO: grochar
336 633135 : if (ckd_sub(u, *u, u2)) {
337 0 : warning(WARN_RANGE, "integer subtraction saturated");
338 0 : return false;
339 : }
340 633135 : break;
341 436600 : case int('*'): // TODO: grochar
342 436600 : if (ckd_mul(u, *u, u2)) {
343 0 : warning(WARN_RANGE, "integer multiplication saturated");
344 0 : return false;
345 : }
346 436600 : break;
347 187710 : case int('/'): // TODO: grochar
348 187710 : if (0 == u2) {
349 0 : error("division by zero");
350 0 : return false;
351 : }
352 187710 : *u /= u2;
353 187710 : break;
354 142213 : case int('%'): // TODO: grochar
355 142213 : if (0 == u2) {
356 0 : error("modulus by zero");
357 0 : return false;
358 : }
359 142213 : *u %= u2;
360 142213 : break;
361 0 : default:
362 0 : assert(0 == "unhandled case of operator");
363 : }
364 : }
365 264 : return result;
366 : }
367 :
368 12684531 : static bool is_valid_term(units *u, int scaling_unit,
369 : bool is_parenthesized, bool is_mandatory)
370 : {
371 12684531 : bool is_negative = false;
372 12684531 : bool is_overflowing = false;
373 12684531 : units saved_u = 0; // for use when reading an overlong number
374 : for (;;)
375 15840261 : if (is_parenthesized && tok.is_space())
376 2864479 : tok.next();
377 12975782 : else if (tok.ch() == int('+')) // TODO: grochar
378 527 : tok.next();
379 12975255 : else if (tok.ch() == int('-')) { // TODO: grochar
380 290724 : tok.next();
381 290724 : is_negative = !is_negative;
382 : }
383 : else
384 12684531 : break;
385 12684531 : int c = tok.ch(); // safely compares to char literals; TODO: grochar
386 12684531 : switch (c) {
387 62322 : case int('|'): // TODO: grochar
388 : // | is not restricted to the outermost level
389 : // tbl uses this
390 62322 : tok.next();
391 62322 : if (!is_valid_term(u, scaling_unit, is_parenthesized, is_mandatory))
392 2472181 : return false;
393 : int tmp, position;
394 62321 : position = (('v' == scaling_unit)
395 62321 : ? curdiv->get_vertical_position().to_units()
396 15412 : : curenv->get_input_line_position().to_units());
397 62321 : if (ckd_sub(&tmp, *u, position)) {
398 0 : tmp = INT_MAX;
399 0 : warning(WARN_RANGE, "integer value saturated");
400 : }
401 62321 : *u = tmp;
402 62321 : if (is_negative)
403 0 : *u = -*u;
404 62321 : return true;
405 2409609 : case int('('): // TODO: grochar
406 2409609 : tok.next();
407 2409609 : c = tok.ch();
408 2409609 : if (int(')') == c) { // TODO: grochar
409 0 : if (is_mandatory)
410 0 : return false;
411 0 : warning(WARN_SYNTAX, "empty parentheses");
412 0 : tok.next();
413 0 : *u = 0;
414 0 : return true;
415 : }
416 2409609 : else if ((c != 0) && (strchr(valid_scaling_units, char(c)) != 0)) {
417 27967 : tok.next();
418 27967 : if (tok.ch() == int(';')) { // TODO: grochar
419 27958 : tok.next();
420 27958 : scaling_unit = c;
421 : }
422 : else {
423 9 : error("expected ';' after scaling unit, got %1",
424 9 : tok.description());
425 9 : return false;
426 : }
427 : }
428 2381642 : else if (';' == c) {
429 127 : scaling_unit = 0;
430 127 : tok.next();
431 : }
432 2409600 : if (!is_valid_expression(u, scaling_unit,
433 : true /* is_parenthesized */, is_mandatory))
434 10 : return false;
435 2409590 : tok.skip_spaces();
436 2409590 : if (tok.ch() != int(')')) { // TODO: grochar
437 15 : if (is_mandatory)
438 15 : return false;
439 0 : warning(WARN_SYNTAX, "expected ')', got %1", tok.description());
440 : }
441 : else
442 2409575 : tok.next();
443 2409575 : if (is_negative) {
444 : // Why? Consider -(INT_MIN) in two's complement.
445 645 : if (ckd_mul(u, *u, -1))
446 0 : warning(WARN_RANGE, "integer multiplication saturated");
447 : }
448 2409575 : return true;
449 137489 : case int('.'): // TODO: grochar
450 137489 : *u = 0;
451 137489 : break;
452 10074861 : case int('0'): // TODO: grochar
453 : case int('1'): // TODO: grochar
454 : case int('2'): // TODO: grochar
455 : case int('3'): // TODO: grochar
456 : case int('4'): // TODO: grochar
457 : case int('5'): // TODO: grochar
458 : case int('6'): // TODO: grochar
459 : case int('7'): // TODO: grochar
460 : case int('8'): // TODO: grochar
461 : case int('9'): // TODO: grochar
462 10074861 : *u = 0;
463 12662192 : do {
464 22737053 : if (!is_overflowing) {
465 22736993 : saved_u = *u;
466 22736993 : if (ckd_mul(u, *u, 10))
467 6 : is_overflowing = true;
468 22736993 : if (ckd_add(u, *u, c - '0'))
469 0 : is_overflowing = true;
470 22736993 : if (is_overflowing)
471 6 : *u = saved_u;
472 : }
473 : // No `else` on overflow; consume and discard further digits.
474 22737053 : tok.next();
475 22737053 : c = tok.ch();
476 22737053 : } while (csdigit(c));
477 10074861 : if (is_overflowing)
478 6 : warning(WARN_RANGE, "integer value saturated");
479 10074861 : break;
480 10 : case int('/'): // TODO: grochar
481 : case int('*'): // TODO: grochar
482 : case int('%'): // TODO: grochar
483 : case int(':'): // TODO: grochar
484 : case int('&'): // TODO: grochar
485 : case int('>'): // TODO: grochar
486 : case int('<'): // TODO: grochar
487 : case int('='): // TODO: grochar
488 10 : warning(WARN_SYNTAX, "empty left operand to '%1' operator",
489 10 : char(c));
490 10 : *u = 0;
491 10 : return !is_mandatory;
492 240 : default:
493 240 : error("ignoring invalid numeric expression starting with %1",
494 240 : tok.description());
495 240 : return false;
496 : }
497 10212350 : int divisor = 1;
498 10212350 : if (tok.ch() == int('.')) { // TODO: grochar
499 292864 : tok.next();
500 : for (;;) {
501 803664 : c = tok.ch();
502 803664 : if (!csdigit(c))
503 292864 : break;
504 : // we may multiply the divisor by 254 later on
505 510800 : if ((divisor <= (INT_MAX / 2540)) && (*u <= ((INT_MAX - 9) / 10)))
506 : {
507 510800 : *u *= 10;
508 510800 : *u += c - '0';
509 510800 : divisor *= 10;
510 : }
511 510800 : tok.next();
512 : }
513 : }
514 10212350 : int si = scaling_unit;
515 10212350 : bool do_next = false;
516 10212350 : if (((c = tok.ch()) != 0)
517 10212350 : && (strchr(valid_scaling_units, c) != 0 /* nullptr */)) {
518 1946788 : switch (scaling_unit) {
519 123 : case int(0): // TODO: grochar; null character, not digit zero
520 : // We know it's a recognized scaling unit because it matched the
521 : // `strchr()` above, so we don't use `tok.description()`.
522 123 : warning(WARN_SCALE, "a scaling unit is not valid in this context"
523 123 : " (got '%1')", char(c));
524 123 : break;
525 1020 : case int('f'): // TODO: grochar
526 1020 : if (c != int('f') && c != int('u')) { // TODO: grochar
527 0 : warning(WARN_SCALE, "'%1' scaling unit invalid in this context;"
528 0 : " use 'f' or 'u'", char(c));
529 0 : break;
530 : }
531 1020 : si = c;
532 1020 : break;
533 144970 : case int('z'): // TODO: grochar
534 144970 : if (c != int('u')
535 65774 : && c != int('z')
536 0 : && c != int('p')
537 0 : && c != int('s')) { // TODO: grochar
538 0 : warning(WARN_SCALE, "'%1' scaling unit invalid in this context;"
539 0 : " use 'z', 'p', 's', or 'u'", char(c));
540 0 : break;
541 : }
542 144970 : si = c;
543 144970 : break;
544 350770 : case int('u'): // TODO: grochar
545 350770 : si = c;
546 350770 : break;
547 1449905 : default:
548 1449905 : if (int('z') == c) { // TODO: grochar
549 0 : warning(WARN_SCALE, "'z' scaling unit invalid in this context");
550 0 : break;
551 : }
552 1449905 : si = c;
553 1449905 : break;
554 : }
555 : // Don't do tok.next() here because the next token might be \s,
556 : // which would affect the interpretation of 'm'.
557 1946788 : do_next = true;
558 : }
559 10212350 : switch (si) {
560 36723 : case int('i'): // TODO: grochar
561 36723 : *u = scale(*u, units_per_inch, divisor);
562 36723 : break;
563 1054 : case int('c'): // TODO: grochar
564 1054 : *u = scale(*u, (units_per_inch * 100), (divisor * 254));
565 1054 : break;
566 9277502 : case int(0): // TODO: grochar; null character, not digit zero
567 : case int('u'): // TODO: grochar
568 9277502 : if (divisor != 1)
569 100 : *u /= divisor;
570 9277502 : break;
571 2340 : case int('f'): // TODO: grochar
572 2340 : *u = scale(*u, 65536, divisor);
573 2340 : break;
574 139639 : case int('p'): // TODO: grochar
575 139639 : *u = scale(*u, units_per_inch, divisor * 72);
576 139639 : break;
577 366 : case int('P'): // TODO: grochar
578 366 : *u = scale(*u, units_per_inch, divisor * 6);
579 366 : break;
580 125584 : case int('m'): // TODO: grochar
581 : {
582 : // Convert to hunits so that with -Tascii 'm' behaves as in nroff.
583 125584 : hunits em = curenv->get_size();
584 125584 : *u = scale(*u, em.is_zero() ? hresolution : em.to_units(),
585 : divisor);
586 : }
587 125584 : break;
588 1912 : case int('M'): // TODO: grochar
589 : {
590 1912 : hunits em = curenv->get_size();
591 1912 : *u = scale(*u, em.is_zero() ? hresolution : em.to_units(),
592 : (divisor * 100));
593 : }
594 1912 : break;
595 57048 : case int('n'): // TODO: grochar
596 : {
597 : // Convert to hunits so that with -Tascii 'n' behaves as in nroff.
598 57048 : hunits en = curenv->get_size() / 2;
599 57048 : *u = scale(*u, en.is_zero() ? hresolution : en.to_units(),
600 : divisor);
601 : }
602 57048 : break;
603 331556 : case int('v'): // TODO: grochar
604 331556 : *u = scale(*u, curenv->get_vertical_spacing().to_units(), divisor);
605 331556 : break;
606 81 : case int('s'): // TODO: grochar
607 81 : while (divisor > INT_MAX / (sizescale * 72)) {
608 0 : divisor /= 10;
609 0 : *u /= 10;
610 : }
611 81 : *u = scale(*u, units_per_inch, divisor * sizescale * 72);
612 81 : break;
613 238545 : case int('z'): // TODO: grochar
614 238545 : *u = scale(*u, sizescale, divisor);
615 238545 : break;
616 0 : default:
617 0 : assert(0 == "unhandled case of scaling unit");
618 : }
619 10212350 : if (do_next)
620 1946788 : tok.next();
621 10212350 : if (is_negative) {
622 289228 : if (ckd_mul(u, *u, -1))
623 0 : warning(WARN_RANGE, "integer multiplication saturated");
624 : }
625 10212350 : return true;
626 : }
627 :
628 2728333 : units scale(units n, units x, units y)
629 : {
630 2728333 : assert(x >= 0);
631 2728333 : assert(y > 0);
632 2728333 : if (0 == x)
633 53924 : return 0;
634 2674409 : if (n >= 0) {
635 2674409 : if (n <= (INT_MAX / x))
636 2674388 : return ((n * x) / y);
637 : }
638 : else {
639 0 : if ((-(unsigned int)(n)) <= ((-(unsigned int)(INT_MIN)) / x))
640 0 : return ((n * x) / y);
641 : }
642 21 : double res = n * double(x) / double(y);
643 21 : if (res > INT_MAX) {
644 4 : warning(WARN_RANGE, "integer value saturated");
645 4 : return INT_MAX;
646 : }
647 17 : else if (res < INT_MIN) {
648 0 : warning(WARN_RANGE, "integer value saturated");
649 0 : return INT_MIN;
650 : }
651 17 : return units(res);
652 : }
653 :
654 6809676 : vunits::vunits(units x)
655 : {
656 6809676 : if (1 == vresolution)
657 4292735 : n = x;
658 : else {
659 : // Don't depend on rounding direction when dividing neg integers.
660 2516941 : int vcrement = (vresolution / 2) - 1;
661 2516941 : bool is_overflowing = false;
662 2516941 : if (x < 0) {
663 8773 : if (ckd_add(&n, -x, vcrement))
664 0 : is_overflowing = true;
665 8773 : n = -n;
666 : }
667 : else {
668 2508168 : if (ckd_add(&n, x, vcrement))
669 1 : is_overflowing = true;
670 : }
671 2516941 : if (is_overflowing) {
672 1 : if (x < 0) {
673 0 : warning(WARN_RANGE, "integer value saturated");
674 0 : n = INT_MIN;
675 : }
676 : else {
677 1 : warning(WARN_RANGE, "integer value saturated");
678 1 : n = INT_MAX;
679 : }
680 : }
681 2516941 : n /= vresolution;
682 : }
683 6809676 : }
684 :
685 77273865 : hunits::hunits(units x)
686 : {
687 77273865 : if (1 == hresolution)
688 24491366 : n = x;
689 : else {
690 : // Don't depend on rounding direction when dividing neg integers.
691 52782499 : int hcrement = (hresolution / 2) - 1;
692 52782499 : bool is_overflowing = false;
693 52782499 : if (x < 0) {
694 518 : if (ckd_add(&n, -x, hcrement))
695 0 : is_overflowing = true;
696 518 : n = -n;
697 : }
698 : else {
699 52781981 : if (ckd_add(&n, x, hcrement))
700 1 : is_overflowing = true;
701 : }
702 52782499 : if (is_overflowing) {
703 1 : if (x < 0) {
704 0 : warning(WARN_RANGE, "integer value saturated");
705 0 : n = INT_MIN;
706 : }
707 : else {
708 1 : warning(WARN_RANGE, "integer value saturated");
709 1 : n = INT_MAX;
710 : }
711 : }
712 52782499 : n /= hresolution;
713 : }
714 77273865 : }
715 :
716 : // Local Variables:
717 : // fill-column: 72
718 : // mode: C++
719 : // End:
720 : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:
|