2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2004, 2009
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
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.
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
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/>. */
22 #include "dictionary.h"
27 object_dictionary number_reg_dictionary(101);
29 int reg::get_value(units * /*d*/)
36 error("can't increment read-only register");
41 error("can't decrement read-only register");
44 void reg::set_increment(units /*n*/)
46 error("can't auto increment read-only register");
49 void reg::alter_format(char /*f*/, int /*w*/)
51 error("can't alter format of read-only register");
54 const char *reg::get_format()
59 void reg::set_value(units /*n*/)
61 error("can't write read-only register");
64 general_reg::general_reg() : format('1'), width(0), inc(0)
68 static char uppercase_array[] = {
69 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
70 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
71 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
75 static char lowercase_array[] = {
76 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
77 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
78 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
82 static const char *number_value_to_ascii(int value, char format, int width)
84 static char buf[128]; // must be at least 21
89 else if (width > int(sizeof(buf) - 2))
90 sprintf(buf, "%.*d", int(sizeof(buf) - 2), int(value));
92 sprintf(buf, "%.*d", width, int(value));
98 // troff uses z and w to represent 10000 and 5000 in Roman
99 // numerals; I can find no historical basis for this usage
100 const char *s = format == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
102 if (n >= 40000 || n <= -40000) {
103 error("magnitude of `%1' too big for i or I format", n);
119 for (int i = 1000; i > 0; i /= 10, s += 2) {
176 // this is a bit tricky
183 *p++ = format == 'a' ? lowercase_array[d - 1] :
184 uppercase_array[d - 1];
187 char *q = buf[0] == '-' ? buf + 1 : buf;
205 const char *general_reg::get_string()
210 return number_value_to_ascii(n, format, width);
214 void general_reg::increment()
221 void general_reg::decrement()
228 void general_reg::set_increment(units n)
233 void general_reg::alter_format(char f, int w)
239 static const char *number_format_to_ascii(char format, int width)
245 if (n > int(sizeof(buf)) - 1)
246 n = int(sizeof(buf)) - 1;
247 sprintf(buf, "%.*d", n, 0);
260 const char *general_reg::get_format()
262 return number_format_to_ascii(format, width);
265 class number_reg : public general_reg {
269 int get_value(units *);
270 void set_value(units);
273 number_reg::number_reg() : value(0)
277 int number_reg::get_value(units *res)
283 void number_reg::set_value(units n)
288 variable_reg::variable_reg(units *p) : ptr(p)
292 void variable_reg::set_value(units n)
297 int variable_reg::get_value(units *res)
303 void define_number_reg()
305 symbol nm = get_name(1);
310 reg *r = (reg *)number_reg_dictionary.lookup(nm);
313 if (!r || !r->get_value(&prev_value))
315 if (get_number(&v, 'u', prev_value)) {
318 number_reg_dictionary.define(nm, r);
321 if (tok.space() && has_arg() && get_number(&v, 'u'))
328 void inline_define_reg()
332 if (!start.delimiter(1))
335 symbol nm = get_name(1);
338 reg *r = (reg *)number_reg_dictionary.lookup(nm);
341 number_reg_dictionary.define(nm, r);
345 if (!r->get_value(&prev_value))
347 if (get_number(&v, 'u', prev_value)) {
350 if (get_number(&v, 'u')) {
353 warning(WARN_DELIM, "closing delimiter does not match");
360 void set_number_reg(symbol nm, units n)
362 reg *r = (reg *)number_reg_dictionary.lookup(nm);
365 number_reg_dictionary.define(nm, r);
370 reg *lookup_number_reg(symbol nm)
372 reg *r = (reg *)number_reg_dictionary.lookup(nm);
374 warning(WARN_REG, "number register `%1' not defined", nm.contents());
376 number_reg_dictionary.define(nm, r);
383 symbol nm = get_name(1);
388 reg *r = (reg *)number_reg_dictionary.lookup(nm);
391 number_reg_dictionary.define(nm, r);
400 } while (csdigit(tok.ch()));
401 r->alter_format('1', n);
403 else if (c == 'i' || c == 'I' || c == 'a' || c == 'A')
405 else if (tok.newline() || tok.eof())
406 warning(WARN_MISSING, "missing number register format");
408 error("bad number register format (got %1)", tok.description());
415 symbol s = get_name();
418 number_reg_dictionary.remove(s);
425 symbol s1 = get_name(1);
427 symbol s2 = get_name(1);
429 if (!number_reg_dictionary.alias(s1, s2))
430 warning(WARN_REG, "number register `%1' not defined", s2.contents());
438 symbol s1 = get_name(1);
440 symbol s2 = get_name(1);
442 number_reg_dictionary.rename(s1, s2);
447 void print_number_regs()
449 object_dictionary_iterator iter(number_reg_dictionary);
452 while (iter.get(&s, (object **)&r)) {
453 assert(!s.is_null());
454 errprint("%1\t", s.contents());
455 const char *p = r->get_string();
464 void init_reg_requests()
466 init_request("rr", remove_reg);
467 init_request("nr", define_number_reg);
468 init_request("af", alter_format);
469 init_request("aln", alias_reg);
470 init_request("rnn", rename_reg);
471 init_request("pnr", print_number_regs);