home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / troff / reg.cc < prev    next >
C/C++ Source or Header  |  1995-06-22  |  9KB  |  459 lines

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