Line data Source code
1 : /* Copyright 1989-2025 Free Software Foundation, Inc. 2 : Written by James Clark (jjc@jclark.com) 3 : 4 : This file is part of groff, the GNU roff typesetting system. 5 : 6 : groff is free software; you can redistribute it and/or modify it under 7 : the terms of the GNU General Public License as published by the Free 8 : Software Foundation, either version 3 of the License, or 9 : (at your option) any later version. 10 : 11 : groff is distributed in the hope that it will be useful, but WITHOUT ANY 12 : WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 : for more details. 15 : 16 : You should have received a copy of the GNU General Public License 17 : along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 : 19 : #ifdef HAVE_CONFIG_H 20 : #include <config.h> 21 : #endif 22 : 23 : #include <assert.h> 24 : #include <ctype.h> 25 : #include <stdlib.h> // strotol() 26 : #include <string.h> // memcpy(), strcpy(), strncmp() 27 : 28 : #include "lib.h" // strsave() 29 : 30 : #include "errarg.h" 31 : #include "error.h" 32 : #include "font.h" 33 : #include "ptable.h" 34 : #include "itable.h" 35 : 36 : // troff has a more elaborate `charinfo` class that stores much more 37 : // information. All libgroff and output drivers need is a way to 38 : // retrieve the object's name as a C string. 39 : class charinfo : glyph { 40 : public: 41 : const char *name; // The glyph name, or a null pointer. 42 : friend class character_indexer; 43 : }; 44 : 45 : // PTABLE(charinfo) is a hash table mapping `const char *` to 46 : // `charinfo *`. 47 : declare_ptable(charinfo) 48 4423604 : implement_ptable(charinfo) 49 : 50 : // ITABLE(charinfo) is a hash table mapping `int >= 0` to `charinfo *`. 51 : declare_itable(charinfo) 52 1756790 : implement_itable(charinfo) 53 : 54 : // This class is a registry storing all named and numbered glyphs known 55 : // so far, assigning a unique index to each glyph. 56 : class character_indexer { 57 : public: 58 : character_indexer(); 59 : ~character_indexer(); 60 : // --------------------- Lookup or creation of a glyph. 61 : glyph *ascii_char_glyph(unsigned char); 62 : glyph *named_char_glyph(const char *); 63 : glyph *numbered_char_glyph(int); 64 : private: 65 : int next_index; // Number of glyphs already allocated. 66 : PTABLE(charinfo) table; // Table mapping name to glyph. 67 : glyph *ascii_glyph[256]; // Shorthand table for looking up 68 : // "charNNN" glyphs. 69 : ITABLE(charinfo) ntable; // Table mapping number to glyph. 70 : enum { NSMALL = 256 }; 71 : glyph *small_number_glyph[NSMALL]; // Shorthand table for looking up 72 : // numbered glyphs with small numbers. 73 : }; 74 : 75 2528 : character_indexer::character_indexer() 76 2528 : : next_index(0) 77 : { 78 : int i; 79 649696 : for (i = 0; i < 256; i++) 80 647168 : ascii_glyph[i] = UNDEFINED_GLYPH; 81 649696 : for (i = 0; i < NSMALL; i++) 82 647168 : small_number_glyph[i] = UNDEFINED_GLYPH; 83 2528 : } 84 : 85 2528 : character_indexer::~character_indexer() 86 : { 87 2528 : } 88 : 89 : // Keep this in sync with "src/roff/troff/input.cpp". 90 : // constexpr // C++11 91 : static const char char_prefix[] = { 'c', 'h', 'a', 'r' }; 92 : // constexpr // C++11 93 : static const size_t char_prefix_len = sizeof char_prefix; 94 : 95 1616660 : glyph *character_indexer::ascii_char_glyph(unsigned char c) 96 : { 97 1616660 : if (UNDEFINED_GLYPH == ascii_glyph[c]) { 98 : char buf[sizeof char_prefix + 3 + 1]; // "char" + nnn + '\0' 99 89073 : (void) memcpy(buf, char_prefix, char_prefix_len); 100 89073 : (void) strcpy(buf + char_prefix_len, i_to_a(c)); 101 89073 : charinfo *ci = new charinfo; 102 89073 : ci->index = next_index++; 103 89073 : ci->number = -1; 104 89073 : ci->name = strsave(buf); 105 89073 : ascii_glyph[c] = ci; 106 : } 107 1616660 : return ascii_glyph[c]; 108 : } 109 : 110 247131 : inline glyph *character_indexer::named_char_glyph(const char *s) 111 : { 112 : // Glyphs with name 'charNNN' are stored only in `ascii_glyph[]`, not 113 : // in the table. Therefore treat them specially here. 114 247131 : if (strncmp(s, char_prefix, char_prefix_len) == 0) { 115 : char *val; 116 0 : long n = strtol((s + char_prefix_len), &val, 10); 117 0 : if ((val != (s + char_prefix_len)) && ('\0' == *val) 118 0 : && (n >= 0) && (n < 256)) 119 0 : return ascii_char_glyph((unsigned char)n); 120 : } 121 247131 : charinfo *ci = table.lookupassoc(&s); 122 247131 : if (0 /* nullptr */ == ci) { 123 100754 : ci = new charinfo[1]; 124 100754 : ci->index = next_index++; 125 100754 : ci->number = -1; 126 100754 : ci->name = table.define(s, ci); 127 : } 128 247131 : return ci; 129 : } 130 : 131 288014 : inline glyph *character_indexer::numbered_char_glyph(int n) 132 : { 133 288014 : if ((n >= 0) && (n < NSMALL)) { 134 215261 : if (UNDEFINED_GLYPH == small_number_glyph[n]) { 135 123601 : charinfo *ci = new charinfo; 136 123601 : ci->index = next_index++; 137 123601 : ci->number = n; 138 123601 : ci->name = 0 /* nullptr */; 139 123601 : small_number_glyph[n] = ci; 140 : } 141 215261 : return small_number_glyph[n]; 142 : } 143 72753 : charinfo *ci = ntable.lookup(n); 144 72753 : if (0 /* nullptr */ == ci) { 145 38531 : ci = new charinfo[1]; 146 38531 : ci->index = next_index++; 147 38531 : ci->number = n; 148 38531 : ci->name = 0 /* nullptr */; 149 38531 : ntable.define(n, ci); 150 : } 151 72753 : return ci; 152 : } 153 : 154 : static character_indexer indexer; 155 : 156 288014 : glyph *number_to_glyph(int n) 157 : { 158 288014 : return indexer.numbered_char_glyph(n); 159 : } 160 : 161 : // troff overrides these functions with its own versions. 162 : 163 1863791 : glyph *name_to_glyph(const char *s) 164 : { 165 1863791 : assert((s != 0 /* nullptr */) && (s[0] != '\0') && (s[0] != ' ')); 166 1863791 : if ('\0' == s[1]) 167 : // \200 and char128 are synonyms 168 1616660 : return indexer.ascii_char_glyph(s[0]); 169 247131 : return indexer.named_char_glyph(s); 170 : } 171 : 172 8076130 : const char *glyph_to_name(glyph *g) 173 : { 174 : // In both libgroff and troff, `charinfo` has `glyph` as a base class. 175 : // But in troff, `charinfo` stores much more information. 176 8076130 : charinfo *ci = reinterpret_cast<charinfo *>(g); 177 8076130 : return ci->name; 178 : } 179 : 180 : // Local Variables: 181 : // fill-column: 72 182 : // mode: C++ 183 : // End: 184 : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72: