LCOV - code coverage report
Current view: top level - libs/libgroff - nametoindex.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 57 61 93.4 %
Date: 2026-01-16 17:51:41 Functions: 18 23 78.3 %
Legend: Lines: hit not hit

          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:

Generated by: LCOV version 1.14