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