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

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 473 lines · 410 code · 38 blank · 25 comment · 81 complexity · 232144ef054a4b9010b038867df16702 MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 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 "dictionary.h"
  19. #include "token.h"
  20. #include "request.h"
  21. #include "reg.h"
  22. object_dictionary number_reg_dictionary(101);
  23. int reg::get_value(units * /*d*/)
  24. {
  25. return 0;
  26. }
  27. void reg::increment()
  28. {
  29. error("can't increment read-only register");
  30. }
  31. void reg::decrement()
  32. {
  33. error("can't decrement read-only register");
  34. }
  35. void reg::set_increment(units /*n*/)
  36. {
  37. error("can't auto increment read-only register");
  38. }
  39. void reg::alter_format(char /*f*/, int /*w*/)
  40. {
  41. error("can't alter format of read-only register");
  42. }
  43. const char *reg::get_format()
  44. {
  45. return "0";
  46. }
  47. void reg::set_value(units /*n*/)
  48. {
  49. error("can't write read-only register");
  50. }
  51. general_reg::general_reg() : format('1'), width(0), inc(0)
  52. {
  53. }
  54. static char uppercase_array[] = {
  55. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
  56. 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
  57. 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
  58. 'Y', 'Z',
  59. };
  60. static char lowercase_array[] = {
  61. 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
  62. 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
  63. 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
  64. 'y', 'z',
  65. };
  66. static const char *number_value_to_ascii(int value, char format, int width)
  67. {
  68. static char buf[128]; // must be at least 21
  69. switch(format) {
  70. case '1':
  71. if (width <= 0)
  72. return i_to_a(value);
  73. else if (width > int(sizeof(buf) - 2))
  74. sprintf(buf, "%.*d", int(sizeof(buf) - 2), int(value));
  75. else
  76. sprintf(buf, "%.*d", width, int(value));
  77. break;
  78. case 'i':
  79. case 'I':
  80. {
  81. char *p = buf;
  82. // troff uses z and w to represent 10000 and 5000 in Roman
  83. // numerals; I can find no historical basis for this usage
  84. const char *s = format == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
  85. int n = int(value);
  86. if (n >= 40000 || n <= -40000) {
  87. error("magnitude of `%1' too big for i or I format", n);
  88. return i_to_a(n);
  89. }
  90. if (n == 0) {
  91. *p++ = '0';
  92. *p = 0;
  93. break;
  94. }
  95. if (n < 0) {
  96. *p++ = '-';
  97. n = -n;
  98. }
  99. while (n >= 10000) {
  100. *p++ = s[0];
  101. n -= 10000;
  102. }
  103. for (int i = 1000; i > 0; i /= 10, s += 2) {
  104. int m = n/i;
  105. n -= m*i;
  106. switch (m) {
  107. case 3:
  108. *p++ = s[2];
  109. /* falls through */
  110. case 2:
  111. *p++ = s[2];
  112. /* falls through */
  113. case 1:
  114. *p++ = s[2];
  115. break;
  116. case 4:
  117. *p++ = s[2];
  118. *p++ = s[1];
  119. break;
  120. case 8:
  121. *p++ = s[1];
  122. *p++ = s[2];
  123. *p++ = s[2];
  124. *p++ = s[2];
  125. break;
  126. case 7:
  127. *p++ = s[1];
  128. *p++ = s[2];
  129. *p++ = s[2];
  130. break;
  131. case 6:
  132. *p++ = s[1];
  133. *p++ = s[2];
  134. break;
  135. case 5:
  136. *p++ = s[1];
  137. break;
  138. case 9:
  139. *p++ = s[2];
  140. *p++ = s[0];
  141. }
  142. }
  143. *p = 0;
  144. break;
  145. }
  146. case 'a':
  147. case 'A':
  148. {
  149. int n = value;
  150. char *p = buf;
  151. if (n == 0) {
  152. *p++ = '0';
  153. *p = 0;
  154. }
  155. else {
  156. if (n < 0) {
  157. n = -n;
  158. *p++ = '-';
  159. }
  160. // this is a bit tricky
  161. while (n > 0) {
  162. int d = n % 26;
  163. if (d == 0)
  164. d = 26;
  165. n -= d;
  166. n /= 26;
  167. *p++ = format == 'a' ? lowercase_array[d - 1] :
  168. uppercase_array[d - 1];
  169. }
  170. *p-- = 0;
  171. char *q = buf[0] == '-' ? buf + 1 : buf;
  172. while (q < p) {
  173. char temp = *q;
  174. *q = *p;
  175. *p = temp;
  176. --p;
  177. ++q;
  178. }
  179. }
  180. break;
  181. }
  182. default:
  183. assert(0);
  184. break;
  185. }
  186. return buf;
  187. }
  188. const char *general_reg::get_string()
  189. {
  190. units n;
  191. if (!get_value(&n))
  192. return "";
  193. return number_value_to_ascii(n, format, width);
  194. }
  195. void general_reg::increment()
  196. {
  197. int n;
  198. if (get_value(&n))
  199. set_value(n + inc);
  200. }
  201. void general_reg::decrement()
  202. {
  203. int n;
  204. if (get_value(&n))
  205. set_value(n - inc);
  206. }
  207. void general_reg::set_increment(units n)
  208. {
  209. inc = n;
  210. }
  211. void general_reg::alter_format(char f, int w)
  212. {
  213. format = f;
  214. width = w;
  215. }
  216. static const char *number_format_to_ascii(char format, int width)
  217. {
  218. static char buf[24];
  219. if (format == '1') {
  220. if (width > 0) {
  221. int n = width;
  222. if (n > int(sizeof(buf)) - 1)
  223. n = int(sizeof(buf)) - 1;
  224. sprintf(buf, "%.*d", n, 0);
  225. return buf;
  226. }
  227. else
  228. return "0";
  229. }
  230. else {
  231. buf[0] = format;
  232. buf[1] = '\0';
  233. return buf;
  234. }
  235. }
  236. const char *general_reg::get_format()
  237. {
  238. return number_format_to_ascii(format, width);
  239. }
  240. class number_reg : public general_reg {
  241. units value;
  242. public:
  243. number_reg();
  244. int get_value(units *);
  245. void set_value(units);
  246. };
  247. number_reg::number_reg() : value(0)
  248. {
  249. }
  250. int number_reg::get_value(units *res)
  251. {
  252. *res = value;
  253. return 1;
  254. }
  255. void number_reg::set_value(units n)
  256. {
  257. value = n;
  258. }
  259. variable_reg::variable_reg(units *p) : ptr(p)
  260. {
  261. }
  262. void variable_reg::set_value(units n)
  263. {
  264. *ptr = n;
  265. }
  266. int variable_reg::get_value(units *res)
  267. {
  268. *res = *ptr;
  269. return 1;
  270. }
  271. void define_number_reg()
  272. {
  273. symbol nm = get_name(1);
  274. if (nm.is_null()) {
  275. skip_line();
  276. return;
  277. }
  278. reg *r = (reg *)number_reg_dictionary.lookup(nm);
  279. units v;
  280. units prev_value;
  281. if (!r || !r->get_value(&prev_value))
  282. prev_value = 0;
  283. if (get_number(&v, 'u', prev_value)) {
  284. if (r == 0) {
  285. r = new number_reg;
  286. number_reg_dictionary.define(nm, r);
  287. }
  288. r->set_value(v);
  289. if (tok.space() && has_arg() && get_number(&v, 'u'))
  290. r->set_increment(v);
  291. }
  292. skip_line();
  293. }
  294. #if 0
  295. void inline_define_reg()
  296. {
  297. token start;
  298. start.next();
  299. if (!start.delimiter(1))
  300. return;
  301. tok.next();
  302. symbol nm = get_name(1);
  303. if (nm.is_null())
  304. return;
  305. reg *r = (reg *)number_reg_dictionary.lookup(nm);
  306. if (r == 0) {
  307. r = new number_reg;
  308. number_reg_dictionary.define(nm, r);
  309. }
  310. units v;
  311. units prev_value;
  312. if (!r->get_value(&prev_value))
  313. prev_value = 0;
  314. if (get_number(&v, 'u', prev_value)) {
  315. r->set_value(v);
  316. if (start != tok) {
  317. if (get_number(&v, 'u')) {
  318. r->set_increment(v);
  319. if (start != tok)
  320. warning(WARN_DELIM, "closing delimiter does not match");
  321. }
  322. }
  323. }
  324. }
  325. #endif
  326. void set_number_reg(symbol nm, units n)
  327. {
  328. reg *r = (reg *)number_reg_dictionary.lookup(nm);
  329. if (r == 0) {
  330. r = new number_reg;
  331. number_reg_dictionary.define(nm, r);
  332. }
  333. r->set_value(n);
  334. }
  335. reg *lookup_number_reg(symbol nm)
  336. {
  337. reg *r = (reg *)number_reg_dictionary.lookup(nm);
  338. if (r == 0) {
  339. warning(WARN_REG, "number register `%1' not defined", nm.contents());
  340. r = new number_reg;
  341. number_reg_dictionary.define(nm, r);
  342. }
  343. return r;
  344. }
  345. void alter_format()
  346. {
  347. symbol nm = get_name(1);
  348. if (nm.is_null()) {
  349. skip_line();
  350. return;
  351. }
  352. reg *r = (reg *)number_reg_dictionary.lookup(nm);
  353. if (r == 0) {
  354. r = new number_reg;
  355. number_reg_dictionary.define(nm, r);
  356. }
  357. tok.skip();
  358. char c = tok.ch();
  359. if (csdigit(c)) {
  360. int n = 0;
  361. do {
  362. ++n;
  363. tok.next();
  364. } while (csdigit(tok.ch()));
  365. r->alter_format('1', n);
  366. }
  367. else if (c == 'i' || c == 'I' || c == 'a' || c == 'A')
  368. r->alter_format(c);
  369. else if (tok.newline() || tok.eof())
  370. warning(WARN_MISSING, "missing number register format");
  371. else
  372. error("bad number register format (got %1)", tok.description());
  373. skip_line();
  374. }
  375. void remove_reg()
  376. {
  377. for (;;) {
  378. symbol s = get_name();
  379. if (s.is_null())
  380. break;
  381. number_reg_dictionary.remove(s);
  382. }
  383. skip_line();
  384. }
  385. void alias_reg()
  386. {
  387. symbol s1 = get_name(1);
  388. if (!s1.is_null()) {
  389. symbol s2 = get_name(1);
  390. if (!s2.is_null()) {
  391. if (!number_reg_dictionary.alias(s1, s2))
  392. warning(WARN_REG, "number register `%1' not defined", s2.contents());
  393. }
  394. }
  395. skip_line();
  396. }
  397. void rename_reg()
  398. {
  399. symbol s1 = get_name(1);
  400. if (!s1.is_null()) {
  401. symbol s2 = get_name(1);
  402. if (!s2.is_null())
  403. number_reg_dictionary.rename(s1, s2);
  404. }
  405. skip_line();
  406. }
  407. void print_number_regs()
  408. {
  409. object_dictionary_iterator iter(number_reg_dictionary);
  410. reg *r;
  411. symbol s;
  412. while (iter.get(&s, (object **)&r)) {
  413. assert(!s.is_null());
  414. errprint("%1\t", s.contents());
  415. const char *p = r->get_string();
  416. if (p)
  417. errprint(p);
  418. errprint("\n");
  419. }
  420. fflush(stderr);
  421. skip_line();
  422. }
  423. void init_reg_requests()
  424. {
  425. init_request("rr", remove_reg);
  426. init_request("nr", define_number_reg);
  427. init_request("af", alter_format);
  428. init_request("aln", alias_reg);
  429. init_request("rnn", rename_reg);
  430. init_request("pnr", print_number_regs);
  431. }