summaryrefslogtreecommitdiffstats
path: root/src/libs/libgroff/nametoindex.cpp
blob: 095a432ef597c75d4d9d311f5e281c8c9ddf6130 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* Copyright (C) 1989-2020 Free Software Foundation, Inc.
     Written by James Clark (jjc@jclark.com)

This file is part of groff.

groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or
(at your option) any later version.

groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include "lib.h"

#include <assert.h>
#include <ctype.h>
#include <stdlib.h>

#include "errarg.h"
#include "error.h"
#include "font.h"
#include "ptable.h"
#include "itable.h"

// Every glyphinfo is actually a charinfo.
class charinfo : glyph {
public:
  const char *name;	// The glyph name, or a null pointer.
  friend class character_indexer;
};

// PTABLE(charinfo) is a hash table mapping 'const char *' to 'charinfo *'.
declare_ptable(charinfo)
implement_ptable(charinfo)

// ITABLE(charinfo) is a hash table mapping 'int >= 0' to 'charinfo *'.
declare_itable(charinfo)
implement_itable(charinfo)

// This class is as a registry storing all named and numbered glyphs known
// so far, and assigns a unique index to each glyph.
class character_indexer {
public:
  character_indexer();
  ~character_indexer();
  // --------------------- Lookup or creation of a glyph.
  glyph *ascii_char_glyph(unsigned char);
  glyph *named_char_glyph(const char *);
  glyph *numbered_char_glyph(int);
private:
  int next_index;		// Number of glyphs already allocated.
  PTABLE(charinfo) table;	// Table mapping name to glyph.
  glyph *ascii_glyph[256];	// Shorthand table for looking up "charNNN"
				// glyphs.
  ITABLE(charinfo) ntable;	// Table mapping number to glyph.
  enum { NSMALL = 256 };
  glyph *small_number_glyph[NSMALL]; // Shorthand table for looking up
				// numbered glyphs with small numbers.
};

character_indexer::character_indexer()
: next_index(0)
{
  int i;
  for (i = 0; i < 256; i++)
    ascii_glyph[i] = UNDEFINED_GLYPH;
  for (i = 0; i < NSMALL; i++)
    small_number_glyph[i] = UNDEFINED_GLYPH;
}

character_indexer::~character_indexer()
{
}

glyph *character_indexer::ascii_char_glyph(unsigned char c)
{
  if (ascii_glyph[c] == UNDEFINED_GLYPH) {
    char buf[4+3+1];
    memcpy(buf, "char", 4);
    strcpy(buf + 4, i_to_a(c));
    charinfo *ci = new charinfo;
    ci->index = next_index++;
    ci->number = -1;
    ci->name = strsave(buf);
    ascii_glyph[c] = ci;
  }
  return ascii_glyph[c];
}

inline glyph *character_indexer::named_char_glyph(const char *s)
{
  // Glyphs with name 'charNNN' are only stored in ascii_glyph[], not
  // in the table.  Therefore treat them specially here.
  if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
    char *val;
    long n = strtol(s + 4, &val, 10);
    if (val != s + 4 && *val == '\0' && n >= 0 && n < 256)
      return ascii_char_glyph((unsigned char)n);
  }
  charinfo *ci = table.lookupassoc(&s);
  if (0 == ci) {
    ci = new charinfo[1];
    ci->index = next_index++;
    ci->number = -1;
    ci->name = table.define(s, ci);
  }
  return ci;
}

inline glyph *character_indexer::numbered_char_glyph(int n)
{
  if (n >= 0 && n < NSMALL) {
    if (small_number_glyph[n] == UNDEFINED_GLYPH) {
      charinfo *ci = new charinfo;
      ci->index = next_index++;
      ci->number = n;
      ci->name = 0;
      small_number_glyph[n] = ci;
    }
    return small_number_glyph[n];
  }
  charinfo *ci = ntable.lookup(n);
  if (0 == ci) {
    ci = new charinfo[1];
    ci->index = next_index++;
    ci->number = n;
    ci->name = 0;
    ntable.define(n, ci);
  }
  return ci;
}

static character_indexer indexer;

glyph *number_to_glyph(int n)
{
  return indexer.numbered_char_glyph(n);
}

// troff overrides this function with its own version.

glyph *name_to_glyph(const char *s)
{
  assert(s != 0 && s[0] != '\0' && s[0] != ' ');
  if (s[1] == '\0')
    // \200 and char128 are synonyms
    return indexer.ascii_char_glyph(s[0]);
  return indexer.named_char_glyph(s);
}

const char *glyph_to_name(glyph *g)
{
  charinfo *ci = (charinfo *)g; // Every glyph is actually a charinfo.
  return ci->name;
}

// Local Variables:
// fill-column: 72
// mode: C++
// End:
// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: