2 * Copyright (c) 2014 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
4 * Copyright (C) 1989 - 1992, 2000, 2001, 2004
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
8 * This 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 2, or (at your option) any later
13 * This 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 along
19 * with groff; see the file COPYING. If not, write to the Free Software
20 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "troff-config.h"
26 #include "dictionary.h"
33 object_dictionary
number_reg_dictionary(101); // FIXME static init -> init fun!
35 int reg::get_value(units
* /*d*/)
42 error("can't increment read-only register");
47 error("can't decrement read-only register");
50 void reg::set_increment(units
/*n*/)
52 error("can't auto increment read-only register");
55 void reg::alter_format(char /*f*/, int /*w*/)
57 error("can't alter format of read-only register");
60 const char *reg::get_format()
65 void reg::set_value(units
/*n*/)
67 error("can't write read-only register");
70 general_reg::general_reg() : format('1'), width(0), inc(0)
74 static char uppercase_array
[] = { // FIXME const
75 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
76 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
77 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
81 static char lowercase_array
[] = { // FIXME const
82 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
83 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
84 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
88 static const char *number_value_to_ascii(int value
, char format
, int width
)
90 static char buf
[128]; // must be at least 21
95 else if (width
> int(sizeof(buf
) - 2))
96 sprintf(buf
, "%.*d", int(sizeof(buf
) - 2), int(value
));
98 sprintf(buf
, "%.*d", width
, int(value
));
104 // troff uses z and w to represent 10000 and 5000 in Roman
105 // numerals; I can find no historical basis for this usage
106 const char *s
= format
== 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
108 if (n
>= 40000 || n
<= -40000) {
109 error("magnitude of `%1' too big for i or I format", n
);
125 for (int i
= 1000; i
> 0; i
/= 10, s
+= 2) {
182 // this is a bit tricky
189 *p
++ = format
== 'a' ? lowercase_array
[d
- 1] :
190 uppercase_array
[d
- 1];
193 char *q
= buf
[0] == '-' ? buf
+ 1 : buf
;
211 const char *general_reg::get_string()
216 return number_value_to_ascii(n
, format
, width
);
219 void general_reg::increment()
226 void general_reg::decrement()
233 void general_reg::set_increment(units n
)
238 void general_reg::alter_format(char f
, int w
)
244 static const char *number_format_to_ascii(char format
, int width
)
250 if (n
> int(sizeof(buf
)) - 1)
251 n
= int(sizeof(buf
)) - 1;
252 sprintf(buf
, "%.*d", n
, 0);
265 const char *general_reg::get_format()
267 return number_format_to_ascii(format
, width
);
277 int get_value(units
*);
278 void set_value(units
);
281 number_reg::number_reg() : value(0)
285 int number_reg::get_value(units
*res
)
291 void number_reg::set_value(units n
)
296 variable_reg::variable_reg(units
*p
) : ptr(p
)
300 void variable_reg::set_value(units n
)
305 int variable_reg::get_value(units
*res
)
311 void define_number_reg()
313 symbol nm
= get_name(1);
318 reg
*r
= (reg
*)number_reg_dictionary
.lookup(nm
);
321 if (!r
|| !r
->get_value(&prev_value
))
323 if (get_number(&v
, 'u', prev_value
)) {
326 number_reg_dictionary
.define(nm
, r
);
329 if (tok
.space() && has_arg() && get_number(&v
, 'u'))
336 void inline_define_reg()
340 if (!start
.delimiter(1))
343 symbol nm
= get_name(1);
346 reg
*r
= (reg
*)number_reg_dictionary
.lookup(nm
);
349 number_reg_dictionary
.define(nm
, r
);
353 if (!r
->get_value(&prev_value
))
355 if (get_number(&v
, 'u', prev_value
)) {
358 if (get_number(&v
, 'u')) {
361 warning(WARN_DELIM
, "closing delimiter does not match");
368 void set_number_reg(symbol nm
, units n
)
370 reg
*r
= (reg
*)number_reg_dictionary
.lookup(nm
);
373 number_reg_dictionary
.define(nm
, r
);
378 reg
*lookup_number_reg(symbol nm
)
380 reg
*r
= (reg
*)number_reg_dictionary
.lookup(nm
);
382 warning(WARN_REG
, "number register `%1' not defined", nm
.contents());
384 number_reg_dictionary
.define(nm
, r
);
391 symbol nm
= get_name(1);
396 reg
*r
= (reg
*)number_reg_dictionary
.lookup(nm
);
399 number_reg_dictionary
.define(nm
, r
);
408 } while (csdigit(tok
.ch()));
409 r
->alter_format('1', n
);
411 else if (c
== 'i' || c
== 'I' || c
== 'a' || c
== 'A')
413 else if (tok
.newline() || tok
.eof())
414 warning(WARN_MISSING
, "missing number register format");
416 error("bad number register format (got %1)", tok
.description());
423 symbol s
= get_name();
426 number_reg_dictionary
.remove(s
);
433 symbol s1
= get_name(1);
435 symbol s2
= get_name(1);
437 if (!number_reg_dictionary
.alias(s1
, s2
))
438 warning(WARN_REG
, "number register `%1' not defined", s2
.contents());
446 symbol s1
= get_name(1);
448 symbol s2
= get_name(1);
450 number_reg_dictionary
.rename(s1
, s2
);
455 void print_number_regs()
457 object_dictionary_iterator
iter(number_reg_dictionary
);
460 while (iter
.get(&s
, (object
**)&r
)) {
461 assert(!s
.is_null());
462 errprint("%1\t", s
.contents());
463 const char *p
= r
->get_string();
472 void init_reg_requests()
474 init_request("rr", remove_reg
);
475 init_request("nr", define_number_reg
);
476 init_request("af", alter_format
);
477 init_request("aln", alias_reg
);
478 init_request("rnn", rename_reg
);
479 init_request("pnr", print_number_regs
);