/contrib/groff/src/roff/troff/number.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 698 lines · 640 code · 28 blank · 30 comment · 157 complexity · 146b9517f2017b14417908eeac07a7b3 MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2004
  3. Free Software Foundation, Inc.
  4. Written by James Clark (jjc@jclark.com)
  5. This file is part of groff.
  6. groff is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation; either version 2, or (at your option) any later
  9. version.
  10. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with groff; see the file COPYING. If not, write to the Free Software
  16. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  17. #include "troff.h"
  18. #include "hvunits.h"
  19. #include "stringclass.h"
  20. #include "mtsm.h"
  21. #include "env.h"
  22. #include "token.h"
  23. #include "div.h"
  24. vunits V0;
  25. hunits H0;
  26. int hresolution = 1;
  27. int vresolution = 1;
  28. int units_per_inch;
  29. int sizescale;
  30. static int parse_expr(units *v, int scale_indicator,
  31. int parenthesised, int rigid = 0);
  32. static int start_number();
  33. int get_vunits(vunits *res, unsigned char si)
  34. {
  35. if (!start_number())
  36. return 0;
  37. units x;
  38. if (parse_expr(&x, si, 0)) {
  39. *res = vunits(x);
  40. return 1;
  41. }
  42. else
  43. return 0;
  44. }
  45. int get_hunits(hunits *res, unsigned char si)
  46. {
  47. if (!start_number())
  48. return 0;
  49. units x;
  50. if (parse_expr(&x, si, 0)) {
  51. *res = hunits(x);
  52. return 1;
  53. }
  54. else
  55. return 0;
  56. }
  57. // for \B
  58. int get_number_rigidly(units *res, unsigned char si)
  59. {
  60. if (!start_number())
  61. return 0;
  62. units x;
  63. if (parse_expr(&x, si, 0, 1)) {
  64. *res = x;
  65. return 1;
  66. }
  67. else
  68. return 0;
  69. }
  70. int get_number(units *res, unsigned char si)
  71. {
  72. if (!start_number())
  73. return 0;
  74. units x;
  75. if (parse_expr(&x, si, 0)) {
  76. *res = x;
  77. return 1;
  78. }
  79. else
  80. return 0;
  81. }
  82. int get_integer(int *res)
  83. {
  84. if (!start_number())
  85. return 0;
  86. units x;
  87. if (parse_expr(&x, 0, 0)) {
  88. *res = x;
  89. return 1;
  90. }
  91. else
  92. return 0;
  93. }
  94. enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT };
  95. static incr_number_result get_incr_number(units *res, unsigned char);
  96. int get_vunits(vunits *res, unsigned char si, vunits prev_value)
  97. {
  98. units v;
  99. switch (get_incr_number(&v, si)) {
  100. case BAD:
  101. return 0;
  102. case ABSOLUTE:
  103. *res = v;
  104. break;
  105. case INCREMENT:
  106. *res = prev_value + v;
  107. break;
  108. case DECREMENT:
  109. *res = prev_value - v;
  110. break;
  111. default:
  112. assert(0);
  113. }
  114. return 1;
  115. }
  116. int get_hunits(hunits *res, unsigned char si, hunits prev_value)
  117. {
  118. units v;
  119. switch (get_incr_number(&v, si)) {
  120. case BAD:
  121. return 0;
  122. case ABSOLUTE:
  123. *res = v;
  124. break;
  125. case INCREMENT:
  126. *res = prev_value + v;
  127. break;
  128. case DECREMENT:
  129. *res = prev_value - v;
  130. break;
  131. default:
  132. assert(0);
  133. }
  134. return 1;
  135. }
  136. int get_number(units *res, unsigned char si, units prev_value)
  137. {
  138. units v;
  139. switch (get_incr_number(&v, si)) {
  140. case BAD:
  141. return 0;
  142. case ABSOLUTE:
  143. *res = v;
  144. break;
  145. case INCREMENT:
  146. *res = prev_value + v;
  147. break;
  148. case DECREMENT:
  149. *res = prev_value - v;
  150. break;
  151. default:
  152. assert(0);
  153. }
  154. return 1;
  155. }
  156. int get_integer(int *res, int prev_value)
  157. {
  158. units v;
  159. switch (get_incr_number(&v, 0)) {
  160. case BAD:
  161. return 0;
  162. case ABSOLUTE:
  163. *res = v;
  164. break;
  165. case INCREMENT:
  166. *res = prev_value + int(v);
  167. break;
  168. case DECREMENT:
  169. *res = prev_value - int(v);
  170. break;
  171. default:
  172. assert(0);
  173. }
  174. return 1;
  175. }
  176. static incr_number_result get_incr_number(units *res, unsigned char si)
  177. {
  178. if (!start_number())
  179. return BAD;
  180. incr_number_result result = ABSOLUTE;
  181. if (tok.ch() == '+') {
  182. tok.next();
  183. result = INCREMENT;
  184. }
  185. else if (tok.ch() == '-') {
  186. tok.next();
  187. result = DECREMENT;
  188. }
  189. if (parse_expr(res, si, 0))
  190. return result;
  191. else
  192. return BAD;
  193. }
  194. static int start_number()
  195. {
  196. while (tok.space())
  197. tok.next();
  198. if (tok.newline()) {
  199. warning(WARN_MISSING, "missing number");
  200. return 0;
  201. }
  202. if (tok.tab()) {
  203. warning(WARN_TAB, "tab character where number expected");
  204. return 0;
  205. }
  206. if (tok.right_brace()) {
  207. warning(WARN_RIGHT_BRACE, "`\\}' where number expected");
  208. return 0;
  209. }
  210. return 1;
  211. }
  212. enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
  213. #define SCALE_INDICATOR_CHARS "icfPmnpuvMsz"
  214. static int parse_term(units *v, int scale_indicator,
  215. int parenthesised, int rigid);
  216. static int parse_expr(units *v, int scale_indicator,
  217. int parenthesised, int rigid)
  218. {
  219. int result = parse_term(v, scale_indicator, parenthesised, rigid);
  220. while (result) {
  221. if (parenthesised)
  222. tok.skip();
  223. int op = tok.ch();
  224. switch (op) {
  225. case '+':
  226. case '-':
  227. case '/':
  228. case '*':
  229. case '%':
  230. case ':':
  231. case '&':
  232. tok.next();
  233. break;
  234. case '>':
  235. tok.next();
  236. if (tok.ch() == '=') {
  237. tok.next();
  238. op = OP_GEQ;
  239. }
  240. else if (tok.ch() == '?') {
  241. tok.next();
  242. op = OP_MAX;
  243. }
  244. break;
  245. case '<':
  246. tok.next();
  247. if (tok.ch() == '=') {
  248. tok.next();
  249. op = OP_LEQ;
  250. }
  251. else if (tok.ch() == '?') {
  252. tok.next();
  253. op = OP_MIN;
  254. }
  255. break;
  256. case '=':
  257. tok.next();
  258. if (tok.ch() == '=')
  259. tok.next();
  260. break;
  261. default:
  262. return result;
  263. }
  264. units v2;
  265. if (!parse_term(&v2, scale_indicator, parenthesised, rigid))
  266. return 0;
  267. int overflow = 0;
  268. switch (op) {
  269. case '<':
  270. *v = *v < v2;
  271. break;
  272. case '>':
  273. *v = *v > v2;
  274. break;
  275. case OP_LEQ:
  276. *v = *v <= v2;
  277. break;
  278. case OP_GEQ:
  279. *v = *v >= v2;
  280. break;
  281. case OP_MIN:
  282. if (*v > v2)
  283. *v = v2;
  284. break;
  285. case OP_MAX:
  286. if (*v < v2)
  287. *v = v2;
  288. break;
  289. case '=':
  290. *v = *v == v2;
  291. break;
  292. case '&':
  293. *v = *v > 0 && v2 > 0;
  294. break;
  295. case ':':
  296. *v = *v > 0 || v2 > 0;
  297. break;
  298. case '+':
  299. if (v2 < 0) {
  300. if (*v < INT_MIN - v2)
  301. overflow = 1;
  302. }
  303. else if (v2 > 0) {
  304. if (*v > INT_MAX - v2)
  305. overflow = 1;
  306. }
  307. if (overflow) {
  308. error("addition overflow");
  309. return 0;
  310. }
  311. *v += v2;
  312. break;
  313. case '-':
  314. if (v2 < 0) {
  315. if (*v > INT_MAX + v2)
  316. overflow = 1;
  317. }
  318. else if (v2 > 0) {
  319. if (*v < INT_MIN + v2)
  320. overflow = 1;
  321. }
  322. if (overflow) {
  323. error("subtraction overflow");
  324. return 0;
  325. }
  326. *v -= v2;
  327. break;
  328. case '*':
  329. if (v2 < 0) {
  330. if (*v > 0) {
  331. if (*v > -(unsigned)INT_MIN / -(unsigned)v2)
  332. overflow = 1;
  333. }
  334. else if (-(unsigned)*v > INT_MAX / -(unsigned)v2)
  335. overflow = 1;
  336. }
  337. else if (v2 > 0) {
  338. if (*v > 0) {
  339. if (*v > INT_MAX / v2)
  340. overflow = 1;
  341. }
  342. else if (-(unsigned)*v > -(unsigned)INT_MIN / v2)
  343. overflow = 1;
  344. }
  345. if (overflow) {
  346. error("multiplication overflow");
  347. return 0;
  348. }
  349. *v *= v2;
  350. break;
  351. case '/':
  352. if (v2 == 0) {
  353. error("division by zero");
  354. return 0;
  355. }
  356. *v /= v2;
  357. break;
  358. case '%':
  359. if (v2 == 0) {
  360. error("modulus by zero");
  361. return 0;
  362. }
  363. *v %= v2;
  364. break;
  365. default:
  366. assert(0);
  367. }
  368. }
  369. return result;
  370. }
  371. static int parse_term(units *v, int scale_indicator,
  372. int parenthesised, int rigid)
  373. {
  374. int negative = 0;
  375. for (;;)
  376. if (parenthesised && tok.space())
  377. tok.next();
  378. else if (tok.ch() == '+')
  379. tok.next();
  380. else if (tok.ch() == '-') {
  381. tok.next();
  382. negative = !negative;
  383. }
  384. else
  385. break;
  386. unsigned char c = tok.ch();
  387. switch (c) {
  388. case '|':
  389. // | is not restricted to the outermost level
  390. // tbl uses this
  391. tok.next();
  392. if (!parse_term(v, scale_indicator, parenthesised, rigid))
  393. return 0;
  394. int tem;
  395. tem = (scale_indicator == 'v'
  396. ? curdiv->get_vertical_position().to_units()
  397. : curenv->get_input_line_position().to_units());
  398. if (tem >= 0) {
  399. if (*v < INT_MIN + tem) {
  400. error("numeric overflow");
  401. return 0;
  402. }
  403. }
  404. else {
  405. if (*v > INT_MAX + tem) {
  406. error("numeric overflow");
  407. return 0;
  408. }
  409. }
  410. *v -= tem;
  411. if (negative) {
  412. if (*v == INT_MIN) {
  413. error("numeric overflow");
  414. return 0;
  415. }
  416. *v = -*v;
  417. }
  418. return 1;
  419. case '(':
  420. tok.next();
  421. c = tok.ch();
  422. if (c == ')') {
  423. if (rigid)
  424. return 0;
  425. warning(WARN_SYNTAX, "empty parentheses");
  426. tok.next();
  427. *v = 0;
  428. return 1;
  429. }
  430. else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
  431. tok.next();
  432. if (tok.ch() == ';') {
  433. tok.next();
  434. scale_indicator = c;
  435. }
  436. else {
  437. error("expected `;' after scale-indicator (got %1)",
  438. tok.description());
  439. return 0;
  440. }
  441. }
  442. else if (c == ';') {
  443. scale_indicator = 0;
  444. tok.next();
  445. }
  446. if (!parse_expr(v, scale_indicator, 1, rigid))
  447. return 0;
  448. tok.skip();
  449. if (tok.ch() != ')') {
  450. if (rigid)
  451. return 0;
  452. warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description());
  453. }
  454. else
  455. tok.next();
  456. if (negative) {
  457. if (*v == INT_MIN) {
  458. error("numeric overflow");
  459. return 0;
  460. }
  461. *v = -*v;
  462. }
  463. return 1;
  464. case '.':
  465. *v = 0;
  466. break;
  467. case '0':
  468. case '1':
  469. case '2':
  470. case '3':
  471. case '4':
  472. case '5':
  473. case '6':
  474. case '7':
  475. case '8':
  476. case '9':
  477. *v = 0;
  478. do {
  479. if (*v > INT_MAX/10) {
  480. error("numeric overflow");
  481. return 0;
  482. }
  483. *v *= 10;
  484. if (*v > INT_MAX - (int(c) - '0')) {
  485. error("numeric overflow");
  486. return 0;
  487. }
  488. *v += c - '0';
  489. tok.next();
  490. c = tok.ch();
  491. } while (csdigit(c));
  492. break;
  493. case '/':
  494. case '*':
  495. case '%':
  496. case ':':
  497. case '&':
  498. case '>':
  499. case '<':
  500. case '=':
  501. warning(WARN_SYNTAX, "empty left operand");
  502. *v = 0;
  503. return rigid ? 0 : 1;
  504. default:
  505. warning(WARN_NUMBER, "numeric expression expected (got %1)",
  506. tok.description());
  507. return 0;
  508. }
  509. int divisor = 1;
  510. if (tok.ch() == '.') {
  511. tok.next();
  512. for (;;) {
  513. c = tok.ch();
  514. if (!csdigit(c))
  515. break;
  516. // we may multiply the divisor by 254 later on
  517. if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) {
  518. *v *= 10;
  519. *v += c - '0';
  520. divisor *= 10;
  521. }
  522. tok.next();
  523. }
  524. }
  525. int si = scale_indicator;
  526. int do_next = 0;
  527. if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
  528. switch (scale_indicator) {
  529. case 'z':
  530. if (c != 'u' && c != 'z') {
  531. warning(WARN_SCALE,
  532. "only `z' and `u' scale indicators valid in this context");
  533. break;
  534. }
  535. si = c;
  536. break;
  537. case 0:
  538. warning(WARN_SCALE, "scale indicator invalid in this context");
  539. break;
  540. case 'u':
  541. si = c;
  542. break;
  543. default:
  544. if (c == 'z') {
  545. warning(WARN_SCALE, "`z' scale indicator invalid in this context");
  546. break;
  547. }
  548. si = c;
  549. break;
  550. }
  551. // Don't do tok.next() here because the next token might be \s, which
  552. // would affect the interpretation of m.
  553. do_next = 1;
  554. }
  555. switch (si) {
  556. case 'i':
  557. *v = scale(*v, units_per_inch, divisor);
  558. break;
  559. case 'c':
  560. *v = scale(*v, units_per_inch*100, divisor*254);
  561. break;
  562. case 0:
  563. case 'u':
  564. if (divisor != 1)
  565. *v /= divisor;
  566. break;
  567. case 'f':
  568. *v = scale(*v, 65536, divisor);
  569. break;
  570. case 'p':
  571. *v = scale(*v, units_per_inch, divisor*72);
  572. break;
  573. case 'P':
  574. *v = scale(*v, units_per_inch, divisor*6);
  575. break;
  576. case 'm':
  577. {
  578. // Convert to hunits so that with -Tascii `m' behaves as in nroff.
  579. hunits em = curenv->get_size();
  580. *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor);
  581. }
  582. break;
  583. case 'M':
  584. {
  585. hunits em = curenv->get_size();
  586. *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100);
  587. }
  588. break;
  589. case 'n':
  590. {
  591. // Convert to hunits so that with -Tascii `n' behaves as in nroff.
  592. hunits en = curenv->get_size()/2;
  593. *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor);
  594. }
  595. break;
  596. case 'v':
  597. *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor);
  598. break;
  599. case 's':
  600. while (divisor > INT_MAX/(sizescale*72)) {
  601. divisor /= 10;
  602. *v /= 10;
  603. }
  604. *v = scale(*v, units_per_inch, divisor*sizescale*72);
  605. break;
  606. case 'z':
  607. *v = scale(*v, sizescale, divisor);
  608. break;
  609. default:
  610. assert(0);
  611. }
  612. if (do_next)
  613. tok.next();
  614. if (negative) {
  615. if (*v == INT_MIN) {
  616. error("numeric overflow");
  617. return 0;
  618. }
  619. *v = -*v;
  620. }
  621. return 1;
  622. }
  623. units scale(units n, units x, units y)
  624. {
  625. assert(x >= 0 && y > 0);
  626. if (x == 0)
  627. return 0;
  628. if (n >= 0) {
  629. if (n <= INT_MAX/x)
  630. return (n*x)/y;
  631. }
  632. else {
  633. if (-(unsigned)n <= -(unsigned)INT_MIN/x)
  634. return (n*x)/y;
  635. }
  636. double res = n*double(x)/double(y);
  637. if (res > INT_MAX) {
  638. error("numeric overflow");
  639. return INT_MAX;
  640. }
  641. else if (res < INT_MIN) {
  642. error("numeric overflow");
  643. return INT_MIN;
  644. }
  645. return int(res);
  646. }
  647. vunits::vunits(units x)
  648. {
  649. // don't depend on the rounding direction for division of negative integers
  650. if (vresolution == 1)
  651. n = x;
  652. else
  653. n = (x < 0
  654. ? -((-x + vresolution/2 - 1)/vresolution)
  655. : (x + vresolution/2 - 1)/vresolution);
  656. }
  657. hunits::hunits(units x)
  658. {
  659. // don't depend on the rounding direction for division of negative integers
  660. if (hresolution == 1)
  661. n = x;
  662. else
  663. n = (x < 0
  664. ? -((-x + hresolution/2 - 1)/hresolution)
  665. : (x + hresolution/2 - 1)/hresolution);
  666. }