1114402Sru// -*- C++ -*-
2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2004
3114402Sru   Free Software Foundation, Inc.
4114402Sru     Written by James Clark (jjc@jclark.com)
5114402Sru
6114402SruThis file is part of groff.
7114402Sru
8114402Srugroff is free software; you can redistribute it and/or modify it under
9114402Sruthe terms of the GNU General Public License as published by the Free
10114402SruSoftware Foundation; either version 2, or (at your option) any later
11114402Sruversion.
12114402Sru
13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
15114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16114402Srufor more details.
17114402Sru
18114402SruYou should have received a copy of the GNU General Public License along
19114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21114402Sru
22114402Sru#include "troff.h"
23114402Sru#include "dictionary.h"
24114402Sru#include "token.h"
25114402Sru#include "request.h"
26114402Sru#include "reg.h"
27114402Sru
28114402Sruobject_dictionary number_reg_dictionary(101);
29114402Sru
30114402Sruint reg::get_value(units * /*d*/)
31114402Sru{
32114402Sru  return 0;
33114402Sru}
34114402Sru
35114402Sruvoid reg::increment()
36114402Sru{
37114402Sru  error("can't increment read-only register");
38114402Sru}
39114402Sru
40114402Sruvoid reg::decrement()
41114402Sru{
42114402Sru  error("can't decrement read-only register");
43114402Sru}
44114402Sru
45114402Sruvoid reg::set_increment(units /*n*/)
46114402Sru{
47114402Sru  error("can't auto increment read-only register");
48114402Sru}
49114402Sru
50114402Sruvoid reg::alter_format(char /*f*/, int /*w*/)
51114402Sru{
52114402Sru  error("can't alter format of read-only register");
53114402Sru}
54114402Sru
55114402Sruconst char *reg::get_format()
56114402Sru{
57114402Sru  return "0";
58114402Sru}
59114402Sru
60114402Sruvoid reg::set_value(units /*n*/)
61114402Sru{
62114402Sru  error("can't write read-only register");
63114402Sru}
64114402Sru
65114402Srugeneral_reg::general_reg() : format('1'), width(0), inc(0)
66114402Sru{
67114402Sru}
68114402Sru
69114402Srustatic char uppercase_array[] = {
70114402Sru  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
71114402Sru  'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
72114402Sru  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
73114402Sru  'Y', 'Z',
74114402Sru};
75114402Sru
76114402Srustatic char lowercase_array[] = {
77114402Sru  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
78114402Sru  'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
79114402Sru  'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
80114402Sru  'y', 'z',
81114402Sru};
82114402Sru
83114402Srustatic const char *number_value_to_ascii(int value, char format, int width)
84114402Sru{
85114402Sru  static char buf[128];		// must be at least 21
86114402Sru  switch(format) {
87114402Sru  case '1':
88114402Sru    if (width <= 0)
89114402Sru      return i_to_a(value);
90114402Sru    else if (width > int(sizeof(buf) - 2))
91114402Sru      sprintf(buf, "%.*d", int(sizeof(buf) - 2), int(value));
92114402Sru    else
93114402Sru      sprintf(buf, "%.*d", width, int(value));
94114402Sru    break;
95114402Sru  case 'i':
96114402Sru  case 'I':
97114402Sru    {
98114402Sru      char *p = buf;
99114402Sru      // troff uses z and w to represent 10000 and 5000 in Roman
100114402Sru      // numerals; I can find no historical basis for this usage
101114402Sru      const char *s = format == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
102114402Sru      int n = int(value);
103114402Sru      if (n >= 40000 || n <= -40000) {
104114402Sru	error("magnitude of `%1' too big for i or I format", n);
105114402Sru	return i_to_a(n);
106114402Sru      }
107114402Sru      if (n == 0) {
108114402Sru	*p++ = '0';
109114402Sru	*p = 0;
110114402Sru	break;
111114402Sru      }
112114402Sru      if (n < 0) {
113114402Sru	*p++ = '-';
114114402Sru	n = -n;
115114402Sru      }
116114402Sru      while (n >= 10000) {
117114402Sru	*p++ = s[0];
118114402Sru	n -= 10000;
119114402Sru      }
120114402Sru      for (int i = 1000; i > 0; i /= 10, s += 2) {
121114402Sru	int m = n/i;
122114402Sru	n -= m*i;
123114402Sru	switch (m) {
124114402Sru	case 3:
125114402Sru	  *p++ = s[2];
126114402Sru	  /* falls through */
127114402Sru	case 2:
128114402Sru	  *p++ = s[2];
129114402Sru	  /* falls through */
130114402Sru	case 1:
131114402Sru	  *p++ = s[2];
132114402Sru	  break;
133114402Sru	case 4:
134114402Sru	  *p++ = s[2];
135114402Sru	  *p++ = s[1];
136114402Sru	  break;
137114402Sru	case 8:
138114402Sru	  *p++ = s[1];
139114402Sru	  *p++ = s[2];
140114402Sru	  *p++ = s[2];
141114402Sru	  *p++ = s[2];
142114402Sru	  break;
143114402Sru	case 7:
144114402Sru	  *p++ = s[1];
145114402Sru	  *p++ = s[2];
146114402Sru	  *p++ = s[2];
147114402Sru	  break;
148114402Sru	case 6:
149114402Sru	  *p++ = s[1];
150114402Sru	  *p++ = s[2];
151114402Sru	  break;
152114402Sru	case 5:
153114402Sru	  *p++ = s[1];
154114402Sru	  break;
155114402Sru	case 9:
156114402Sru	  *p++ = s[2];
157114402Sru	  *p++ = s[0];
158114402Sru	}
159114402Sru      }
160114402Sru      *p = 0;
161114402Sru      break;
162114402Sru    }
163114402Sru  case 'a':
164114402Sru  case 'A':
165114402Sru    {
166114402Sru      int n = value;
167114402Sru      char *p = buf;
168114402Sru      if (n == 0) {
169114402Sru	*p++ = '0';
170114402Sru	*p = 0;
171114402Sru      }
172114402Sru      else {
173114402Sru	if (n < 0) {
174114402Sru	  n = -n;
175114402Sru	  *p++ = '-';
176114402Sru	}
177114402Sru	// this is a bit tricky
178114402Sru	while (n > 0) {
179114402Sru	  int d = n % 26;
180114402Sru	  if (d == 0)
181114402Sru	    d = 26;
182114402Sru	  n -= d;
183114402Sru	  n /= 26;
184114402Sru	  *p++ = format == 'a' ? lowercase_array[d - 1] :
185114402Sru				 uppercase_array[d - 1];
186114402Sru	}
187114402Sru	*p-- = 0;
188114402Sru	char *q = buf[0] == '-' ? buf + 1 : buf;
189114402Sru	while (q < p) {
190114402Sru	  char temp = *q;
191114402Sru	  *q = *p;
192114402Sru	  *p = temp;
193114402Sru	  --p;
194114402Sru	  ++q;
195114402Sru	}
196114402Sru      }
197114402Sru      break;
198114402Sru    }
199114402Sru  default:
200114402Sru    assert(0);
201114402Sru    break;
202114402Sru  }
203114402Sru  return buf;
204114402Sru}
205114402Sru
206114402Sruconst char *general_reg::get_string()
207114402Sru{
208114402Sru  units n;
209114402Sru  if (!get_value(&n))
210114402Sru    return "";
211114402Sru  return number_value_to_ascii(n, format, width);
212114402Sru}
213114402Sru
214114402Sru
215114402Sruvoid general_reg::increment()
216114402Sru{
217114402Sru  int n;
218114402Sru  if (get_value(&n))
219114402Sru    set_value(n + inc);
220114402Sru}
221114402Sru
222114402Sruvoid general_reg::decrement()
223114402Sru{
224114402Sru  int n;
225114402Sru  if (get_value(&n))
226114402Sru    set_value(n - inc);
227114402Sru}
228114402Sru
229114402Sruvoid general_reg::set_increment(units n)
230114402Sru{
231114402Sru  inc = n;
232114402Sru}
233114402Sru
234114402Sruvoid general_reg::alter_format(char f, int w)
235114402Sru{
236114402Sru  format = f;
237114402Sru  width = w;
238114402Sru}
239114402Sru
240114402Srustatic const char *number_format_to_ascii(char format, int width)
241114402Sru{
242114402Sru  static char buf[24];
243114402Sru  if (format == '1') {
244114402Sru    if (width > 0) {
245114402Sru      int n = width;
246114402Sru      if (n > int(sizeof(buf)) - 1)
247114402Sru	n = int(sizeof(buf)) - 1;
248114402Sru      sprintf(buf, "%.*d", n, 0);
249114402Sru      return buf;
250114402Sru    }
251114402Sru    else
252114402Sru      return "0";
253114402Sru  }
254114402Sru  else {
255114402Sru    buf[0] = format;
256114402Sru    buf[1] = '\0';
257114402Sru    return buf;
258114402Sru  }
259114402Sru}
260114402Sru
261114402Sruconst char *general_reg::get_format()
262114402Sru{
263114402Sru  return number_format_to_ascii(format, width);
264114402Sru}
265114402Sru
266114402Sruclass number_reg : public general_reg {
267114402Sru  units value;
268114402Srupublic:
269114402Sru  number_reg();
270114402Sru  int get_value(units *);
271114402Sru  void set_value(units);
272114402Sru};
273114402Sru
274114402Srunumber_reg::number_reg() : value(0)
275114402Sru{
276114402Sru}
277114402Sru
278114402Sruint number_reg::get_value(units *res)
279114402Sru{
280114402Sru  *res = value;
281114402Sru  return 1;
282114402Sru}
283114402Sru
284114402Sruvoid number_reg::set_value(units n)
285114402Sru{
286114402Sru  value = n;
287114402Sru}
288114402Sru
289114402Sruvariable_reg::variable_reg(units *p) : ptr(p)
290114402Sru{
291114402Sru}
292114402Sru
293114402Sruvoid variable_reg::set_value(units n)
294114402Sru{
295114402Sru  *ptr = n;
296114402Sru}
297114402Sru
298114402Sruint variable_reg::get_value(units *res)
299114402Sru{
300114402Sru  *res = *ptr;
301114402Sru  return 1;
302114402Sru}
303114402Sru
304114402Sruvoid define_number_reg()
305114402Sru{
306114402Sru  symbol nm = get_name(1);
307114402Sru  if (nm.is_null()) {
308114402Sru    skip_line();
309114402Sru    return;
310114402Sru  }
311114402Sru  reg *r = (reg *)number_reg_dictionary.lookup(nm);
312114402Sru  units v;
313114402Sru  units prev_value;
314114402Sru  if (!r || !r->get_value(&prev_value))
315114402Sru    prev_value = 0;
316114402Sru  if (get_number(&v, 'u', prev_value)) {
317114402Sru    if (r == 0) {
318114402Sru      r = new number_reg;
319114402Sru      number_reg_dictionary.define(nm, r);
320114402Sru    }
321114402Sru    r->set_value(v);
322114402Sru    if (tok.space() && has_arg() && get_number(&v, 'u'))
323114402Sru      r->set_increment(v);
324114402Sru  }
325114402Sru  skip_line();
326114402Sru}
327114402Sru
328114402Sru#if 0
329114402Sruvoid inline_define_reg()
330114402Sru{
331114402Sru  token start;
332114402Sru  start.next();
333114402Sru  if (!start.delimiter(1))
334114402Sru    return;
335114402Sru  tok.next();
336114402Sru  symbol nm = get_name(1);
337114402Sru  if (nm.is_null())
338114402Sru    return;
339114402Sru  reg *r = (reg *)number_reg_dictionary.lookup(nm);
340114402Sru  if (r == 0) {
341114402Sru    r = new number_reg;
342114402Sru    number_reg_dictionary.define(nm, r);
343114402Sru  }
344114402Sru  units v;
345114402Sru  units prev_value;
346114402Sru  if (!r->get_value(&prev_value))
347114402Sru    prev_value = 0;
348114402Sru  if (get_number(&v, 'u', prev_value)) {
349114402Sru    r->set_value(v);
350114402Sru    if (start != tok) {
351114402Sru      if (get_number(&v, 'u')) {
352114402Sru	r->set_increment(v);
353114402Sru	if (start != tok)
354114402Sru	  warning(WARN_DELIM, "closing delimiter does not match");
355114402Sru      }
356114402Sru    }
357114402Sru  }
358114402Sru}
359114402Sru#endif
360114402Sru
361114402Sruvoid set_number_reg(symbol nm, units n)
362114402Sru{
363114402Sru  reg *r = (reg *)number_reg_dictionary.lookup(nm);
364114402Sru  if (r == 0) {
365114402Sru    r = new number_reg;
366114402Sru    number_reg_dictionary.define(nm, r);
367114402Sru  }
368114402Sru  r->set_value(n);
369114402Sru}
370114402Sru
371114402Srureg *lookup_number_reg(symbol nm)
372114402Sru{
373114402Sru  reg *r = (reg *)number_reg_dictionary.lookup(nm);
374114402Sru  if (r == 0) {
375114402Sru    warning(WARN_REG, "number register `%1' not defined", nm.contents());
376114402Sru    r = new number_reg;
377114402Sru    number_reg_dictionary.define(nm, r);
378114402Sru  }
379114402Sru  return r;
380114402Sru}
381114402Sru
382114402Sruvoid alter_format()
383114402Sru{
384114402Sru  symbol nm = get_name(1);
385114402Sru  if (nm.is_null()) {
386114402Sru    skip_line();
387114402Sru    return;
388114402Sru  }
389114402Sru  reg *r = (reg *)number_reg_dictionary.lookup(nm);
390114402Sru  if (r == 0) {
391114402Sru    r = new number_reg;
392114402Sru    number_reg_dictionary.define(nm, r);
393114402Sru  }
394114402Sru  tok.skip();
395114402Sru  char c = tok.ch();
396114402Sru  if (csdigit(c)) {
397114402Sru    int n = 0;
398114402Sru    do {
399114402Sru      ++n;
400114402Sru      tok.next();
401114402Sru    } while (csdigit(tok.ch()));
402114402Sru    r->alter_format('1', n);
403114402Sru  }
404114402Sru  else if (c == 'i' || c == 'I' || c == 'a' || c == 'A')
405114402Sru    r->alter_format(c);
406114402Sru  else if (tok.newline() || tok.eof())
407114402Sru    warning(WARN_MISSING, "missing number register format");
408114402Sru  else
409114402Sru    error("bad number register format (got %1)", tok.description());
410114402Sru  skip_line();
411114402Sru}
412114402Sru
413114402Sruvoid remove_reg()
414114402Sru{
415114402Sru  for (;;) {
416114402Sru    symbol s = get_name();
417114402Sru    if (s.is_null())
418114402Sru      break;
419114402Sru    number_reg_dictionary.remove(s);
420114402Sru  }
421114402Sru  skip_line();
422114402Sru}
423114402Sru
424114402Sruvoid alias_reg()
425114402Sru{
426114402Sru  symbol s1 = get_name(1);
427114402Sru  if (!s1.is_null()) {
428114402Sru    symbol s2 = get_name(1);
429114402Sru    if (!s2.is_null()) {
430114402Sru      if (!number_reg_dictionary.alias(s1, s2))
431114402Sru	warning(WARN_REG, "number register `%1' not defined", s2.contents());
432114402Sru    }
433114402Sru  }
434114402Sru  skip_line();
435114402Sru}
436114402Sru
437114402Sruvoid rename_reg()
438114402Sru{
439114402Sru  symbol s1 = get_name(1);
440114402Sru  if (!s1.is_null()) {
441114402Sru    symbol s2 = get_name(1);
442114402Sru    if (!s2.is_null())
443114402Sru      number_reg_dictionary.rename(s1, s2);
444114402Sru  }
445114402Sru  skip_line();
446114402Sru}
447114402Sru
448114402Sruvoid print_number_regs()
449114402Sru{
450114402Sru  object_dictionary_iterator iter(number_reg_dictionary);
451114402Sru  reg *r;
452114402Sru  symbol s;
453114402Sru  while (iter.get(&s, (object **)&r)) {
454114402Sru    assert(!s.is_null());
455114402Sru    errprint("%1\t", s.contents());
456114402Sru    const char *p = r->get_string();
457114402Sru    if (p)
458114402Sru      errprint(p);
459114402Sru    errprint("\n");
460114402Sru  }
461114402Sru  fflush(stderr);
462114402Sru  skip_line();
463114402Sru}
464114402Sru
465114402Sruvoid init_reg_requests()
466114402Sru{
467114402Sru  init_request("rr", remove_reg);
468114402Sru  init_request("nr", define_number_reg);
469114402Sru  init_request("af", alter_format);
470114402Sru  init_request("aln", alias_reg);
471114402Sru  init_request("rnn", rename_reg);
472114402Sru  init_request("pnr", print_number_regs);
473114402Sru}
474