1 /*        Id: chars.c,v 1.78 2018/12/15 19:30:26 schwarze Exp  */
2 /*
3  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #include "config.h"
19 
20 #include <sys/types.h>
21 
22 #include <assert.h>
23 #include <ctype.h>
24 #include <stddef.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "mandoc.h"
31 #include "mandoc_aux.h"
32 #include "mandoc_ohash.h"
33 #include "libmandoc.h"
34 
35 struct    ln {
36           const char            roffcode[16];
37           const char           *ascii;
38           int                   unicode;
39 };
40 
41 /* Special break control characters. */
42 static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' };
43 static const char ascii_break[2] = { ASCII_BREAK, '\0' };
44 
45 static struct ln lines[] = {
46 
47           /* Spacing. */
48           { " ",                        ascii_nbrsp,        0x00a0    },
49           { "~",                        ascii_nbrsp,        0x00a0    },
50           { "0",                        " ",                0x2002    },
51           { ":",                        ascii_break,        0         },
52 
53           /* Lines. */
54           { "ba",                       "|",                0x007c    },
55           { "br",                       "|",                0x2502    },
56           { "ul",                       "_",                0x005f    },
57           { "_",                        "_",                0x005f    },
58           { "ru",                       "_",                0x005f    },
59           { "rn",                       "-",                0x203e    },
60           { "bb",                       "|",                0x00a6    },
61           { "sl",                       "/",                0x002f    },
62           { "rs",                       "\\",               0x005c    },
63 
64           /* Text markers. */
65           { "ci",                       "O",                0x25cb    },
66           { "bu",                       "+\bo",             0x2022    },
67           { "dd",                       "<**>",             0x2021    },
68           { "dg",                       "<*>",              0x2020    },
69           { "lz",                       "<>",               0x25ca    },
70           { "sq",                       "[]",               0x25a1    },
71           { "ps",                       "<paragraph>",      0x00b6    },
72           { "sc",                       "<section>",        0x00a7    },
73           { "lh",                       "<=",               0x261c    },
74           { "rh",                       "=>",               0x261e    },
75           { "at",                       "@",                0x0040    },
76           { "sh",                       "#",                0x0023    },
77           { "CR",                       "<cr>",             0x21b5    },
78           { "OK",                       "\\/",              0x2713    },
79           { "CL",                       "C",                0x2663    },
80           { "SP",                       "S",                0x2660    },
81           { "HE",                       "H",                0x2665    },
82           { "DI",                       "D",                0x2666    },
83 
84           /* Legal symbols. */
85           { "co",                       "(C)",              0x00a9    },
86           { "rg",                       "(R)",              0x00ae    },
87           { "tm",                       "tm",               0x2122    },
88 
89           /* Punctuation. */
90           { "em",                       "--",               0x2014    },
91           { "en",                       "-",                0x2013    },
92           { "hy",                       "-",                0x2010    },
93           { "e",                        "\\",               0x005c    },
94           { ".",                        ".",                0x002e    },
95           { "r!",                       "!",                0x00a1    },
96           { "r?",                       "?",                0x00bf    },
97 
98           /* Quotes. */
99           { "Bq",                       ",,",               0x201e    },
100           { "bq",                       ",",                0x201a    },
101           { "lq",                       "\"",               0x201c    },
102           { "rq",                       "\"",               0x201d    },
103           { "Lq",                       "\"",               0x201c    },
104           { "Rq",                       "\"",               0x201d    },
105           { "oq",                       "`",                0x2018    },
106           { "cq",                       "\'",               0x2019    },
107           { "aq",                       "\'",               0x0027    },
108           { "dq",                       "\"",               0x0022    },
109           { "Fo",                       "<<",               0x00ab    },
110           { "Fc",                       ">>",               0x00bb    },
111           { "fo",                       "<",                0x2039    },
112           { "fc",                       ">",                0x203a    },
113 
114           /* Brackets. */
115           { "lB",                       "[",                0x005b    },
116           { "rB",                       "]",                0x005d    },
117           { "lC",                       "{",                0x007b    },
118           { "rC",                       "}",                0x007d    },
119           { "la",                       "<",                0x27e8    },
120           { "ra",                       ">",                0x27e9    },
121           { "bv",                       "|",                0x23aa    },
122           { "braceex",                  "|",                0x23aa    },
123           { "bracketlefttp",  "|",                0x23a1    },
124           { "bracketleftbt",  "|",                0x23a3    },
125           { "bracketleftex",  "|",                0x23a2    },
126           { "bracketrighttp", "|",                0x23a4    },
127           { "bracketrightbt", "|",                0x23a6    },
128           { "bracketrightex", "|",                0x23a5    },
129           { "lt",                       ",-",               0x23a7    },
130           { "bracelefttp",    ",-",               0x23a7    },
131           { "lk",                       "{",                0x23a8    },
132           { "braceleftmid",   "{",                0x23a8    },
133           { "lb",                       "`-",               0x23a9    },
134           { "braceleftbt",    "`-",               0x23a9    },
135           { "braceleftex",    "|",                0x23aa    },
136           { "rt",                       "-.",               0x23ab    },
137           { "bracerighttp",   "-.",               0x23ab    },
138           { "rk",                       "}",                0x23ac    },
139           { "bracerightmid",  "}",                0x23ac    },
140           { "rb",                       "-\'",              0x23ad    },
141           { "bracerightbt",   "-\'",              0x23ad    },
142           { "bracerightex",   "|",                0x23aa    },
143           { "parenlefttp",    "/",                0x239b    },
144           { "parenleftbt",    "\\",               0x239d    },
145           { "parenleftex",    "|",                0x239c    },
146           { "parenrighttp",   "\\",               0x239e    },
147           { "parenrightbt",   "/",                0x23a0    },
148           { "parenrightex",   "|",                0x239f    },
149 
150           /* Arrows and lines. */
151           { "<-",                       "<-",               0x2190    },
152           { "->",                       "->",               0x2192    },
153           { "<>",                       "<->",              0x2194    },
154           { "da",                       "|\bv",             0x2193    },
155           { "ua",                       "|\b^",             0x2191    },
156           { "va",                       "^v",               0x2195    },
157           { "lA",                       "<=",               0x21d0    },
158           { "rA",                       "=>",               0x21d2    },
159           { "hA",                       "<=>",              0x21d4    },
160           { "uA",                       "=\b^",             0x21d1    },
161           { "dA",                       "=\bv",             0x21d3    },
162           { "vA",                       "^=v",              0x21d5    },
163           { "an",                       "-",                0x23af    },
164 
165           /* Logic. */
166           { "AN",                       "^",                0x2227    },
167           { "OR",                       "v",                0x2228    },
168           { "no",                       "~",                0x00ac    },
169           { "tno",            "~",                0x00ac    },
170           { "te",                       "<there\037exists>", 0x2203 },
171           { "fa",                       "<for\037all>",     0x2200    },
172           { "st",                       "<such\037that>", 0x220b },
173           { "tf",                       "<therefore>",      0x2234    },
174           { "3d",                       "<therefore>",      0x2234    },
175           { "or",                       "|",                0x007c    },
176 
177           /* Mathematicals. */
178           { "pl",                       "+",                0x002b    },
179           { "mi",                       "-",                0x2212    },
180           { "-",                        "-",                0x002d    },
181           { "-+",                       "-+",               0x2213    },
182           { "+-",                       "+-",               0x00b1    },
183           { "t+-",            "+-",               0x00b1    },
184           { "pc",                       ".",                0x00b7    },
185           { "md",                       ".",                0x22c5    },
186           { "mu",                       "x",                0x00d7    },
187           { "tmu",            "x",                0x00d7    },
188           { "c*",                       "O\bx",             0x2297    },
189           { "c+",                       "O\b+",             0x2295    },
190           { "di",                       "/",                0x00f7    },
191           { "tdi",            "/",                0x00f7    },
192           { "f/",                       "/",                0x2044    },
193           { "**",                       "*",                0x2217    },
194           { "<=",                       "<=",               0x2264    },
195           { ">=",                       ">=",               0x2265    },
196           { "<<",                       "<<",               0x226a    },
197           { ">>",                       ">>",               0x226b    },
198           { "eq",                       "=",                0x003d    },
199           { "!=",                       "!=",               0x2260    },
200           { "==",                       "==",               0x2261    },
201           { "ne",                       "!==",              0x2262    },
202           { "ap",                       "~",                0x223c    },
203           { "|=",                       "-~",               0x2243    },
204           { "=~",                       "=~",               0x2245    },
205           { "~~",                       "~~",               0x2248    },
206           { "~=",                       "~=",               0x2248    },
207           { "pt",                       "<proportional\037to>", 0x221d },
208           { "es",                       "{}",               0x2205    },
209           { "mo",                       "<element\037of>", 0x2208 },
210           { "nm",                       "<not\037element\037of>", 0x2209 },
211           { "sb",                       "<proper\037subset>", 0x2282 },
212           { "nb",                       "<not\037subset>", 0x2284 },
213           { "sp",                       "<proper\037superset>", 0x2283 },
214           { "nc",                       "<not\037superset>", 0x2285 },
215           { "ib",                       "<subset\037or\037equal>", 0x2286 },
216           { "ip",                       "<superset\037or\037equal>", 0x2287 },
217           { "ca",                       "<intersection>", 0x2229 },
218           { "cu",                       "<union>",          0x222a    },
219           { "/_",                       "<angle>",          0x2220    },
220           { "pp",                       "<perpendicular>", 0x22a5 },
221           { "is",                       "<integral>",       0x222b    },
222           { "integral",                 "<integral>",       0x222b    },
223           { "sum",            "<sum>",  0x2211    },
224           { "product",                  "<product>",        0x220f    },
225           { "coproduct",                "<coproduct>",      0x2210    },
226           { "gr",                       "<nabla>",          0x2207    },
227           { "sr",                       "<sqrt>", 0x221a    },
228           { "sqrt",           "<sqrt>", 0x221a    },
229           { "lc",                       "|~",               0x2308    },
230           { "rc",                       "~|",               0x2309    },
231           { "lf",                       "|_",               0x230a    },
232           { "rf",                       "_|",               0x230b    },
233           { "if",                       "<infinity>",       0x221e    },
234           { "Ah",                       "<Aleph>",          0x2135    },
235           { "Im",                       "<Im>",             0x2111    },
236           { "Re",                       "<Re>",             0x211c    },
237           { "wp",                       "p",                0x2118    },
238           { "pd",                       "<del>",  0x2202    },
239           { "-h",                       "/h",               0x210f    },
240           { "hbar",           "/h",               0x210f    },
241           { "12",                       "1/2",              0x00bd    },
242           { "14",                       "1/4",              0x00bc    },
243           { "34",                       "3/4",              0x00be    },
244           { "18",                       "1/8",              0x215B    },
245           { "38",                       "3/8",              0x215C    },
246           { "58",                       "5/8",              0x215D    },
247           { "78",                       "7/8",              0x215E    },
248           { "S1",                       "^1",               0x00B9    },
249           { "S2",                       "^2",               0x00B2    },
250           { "S3",                       "^3",               0x00B3    },
251 
252           /* Ligatures. */
253           { "ff",                       "ff",               0xfb00    },
254           { "fi",                       "fi",               0xfb01    },
255           { "fl",                       "fl",               0xfb02    },
256           { "Fi",                       "ffi",              0xfb03    },
257           { "Fl",                       "ffl",              0xfb04    },
258           { "AE",                       "AE",               0x00c6    },
259           { "ae",                       "ae",               0x00e6    },
260           { "OE",                       "OE",               0x0152    },
261           { "oe",                       "oe",               0x0153    },
262           { "ss",                       "ss",               0x00df    },
263           { "IJ",                       "IJ",               0x0132    },
264           { "ij",                       "ij",               0x0133    },
265 
266           /* Accents. */
267           { "a\"",            "\"",               0x02dd    },
268           { "a-",                       "-",                0x00af    },
269           { "a.",                       ".",                0x02d9    },
270           { "a^",                       "^",                0x005e    },
271           { "aa",                       "\'",               0x00b4    },
272           { "\'",                       "\'",               0x00b4    },
273           { "ga",                       "`",                0x0060    },
274           { "`",                        "`",                0x0060    },
275           { "ab",                       "'\b`",             0x02d8    },
276           { "ac",                       ",",                0x00b8    },
277           { "ad",                       "\"",               0x00a8    },
278           { "ah",                       "v",                0x02c7    },
279           { "ao",                       "o",                0x02da    },
280           { "a~",                       "~",                0x007e    },
281           { "ho",                       ",",                0x02db    },
282           { "ha",                       "^",                0x005e    },
283           { "ti",                       "~",                0x007e    },
284           { "u02DC",                    "~",                0x02dc    },
285 
286           /* Accented letters. */
287           { "'A",                       "'\bA",             0x00c1    },
288           { "'E",                       "'\bE",             0x00c9    },
289           { "'I",                       "'\bI",             0x00cd    },
290           { "'O",                       "'\bO",             0x00d3    },
291           { "'U",                       "'\bU",             0x00da    },
292           { "'Y",                       "'\bY",             0x00dd    },
293           { "'a",                       "'\ba",             0x00e1    },
294           { "'e",                       "'\be",             0x00e9    },
295           { "'i",                       "'\bi",             0x00ed    },
296           { "'o",                       "'\bo",             0x00f3    },
297           { "'u",                       "'\bu",             0x00fa    },
298           { "'y",                       "'\by",             0x00fd    },
299           { "`A",                       "`\bA",             0x00c0    },
300           { "`E",                       "`\bE",             0x00c8    },
301           { "`I",                       "`\bI",             0x00cc    },
302           { "`O",                       "`\bO",             0x00d2    },
303           { "`U",                       "`\bU",             0x00d9    },
304           { "`a",                       "`\ba",             0x00e0    },
305           { "`e",                       "`\be",             0x00e8    },
306           { "`i",                       "`\bi",             0x00ec    },
307           { "`o",                       "`\bo",             0x00f2    },
308           { "`u",                       "`\bu",             0x00f9    },
309           { "~A",                       "~\bA",             0x00c3    },
310           { "~N",                       "~\bN",             0x00d1    },
311           { "~O",                       "~\bO",             0x00d5    },
312           { "~a",                       "~\ba",             0x00e3    },
313           { "~n",                       "~\bn",             0x00f1    },
314           { "~o",                       "~\bo",             0x00f5    },
315           { ":A",                       "\"\bA",  0x00c4    },
316           { ":E",                       "\"\bE",  0x00cb    },
317           { ":I",                       "\"\bI",  0x00cf    },
318           { ":O",                       "\"\bO",  0x00d6    },
319           { ":U",                       "\"\bU",  0x00dc    },
320           { ":a",                       "\"\ba",  0x00e4    },
321           { ":e",                       "\"\be",  0x00eb    },
322           { ":i",                       "\"\bi",  0x00ef    },
323           { ":o",                       "\"\bo",  0x00f6    },
324           { ":u",                       "\"\bu",  0x00fc    },
325           { ":y",                       "\"\by",  0x00ff    },
326           { "^A",                       "^\bA",             0x00c2    },
327           { "^E",                       "^\bE",             0x00ca    },
328           { "^I",                       "^\bI",             0x00ce    },
329           { "^O",                       "^\bO",             0x00d4    },
330           { "^U",                       "^\bU",             0x00db    },
331           { "^a",                       "^\ba",             0x00e2    },
332           { "^e",                       "^\be",             0x00ea    },
333           { "^i",                       "^\bi",             0x00ee    },
334           { "^o",                       "^\bo",             0x00f4    },
335           { "^u",                       "^\bu",             0x00fb    },
336           { ",C",                       ",\bC",             0x00c7    },
337           { ",c",                       ",\bc",             0x00e7    },
338           { "/L",                       "/\bL",             0x0141    },
339           { "/l",                       "/\bl",             0x0142    },
340           { "/O",                       "/\bO",             0x00d8    },
341           { "/o",                       "/\bo",             0x00f8    },
342           { "oA",                       "o\bA",             0x00c5    },
343           { "oa",                       "o\ba",             0x00e5    },
344 
345           /* Special letters. */
346           { "-D",                       "Dh",               0x00d0    },
347           { "Sd",                       "dh",               0x00f0    },
348           { "TP",                       "Th",               0x00de    },
349           { "Tp",                       "th",               0x00fe    },
350           { ".i",                       "i",                0x0131    },
351           { ".j",                       "j",                0x0237    },
352 
353           /* Currency. */
354           { "Do",                       "$",                0x0024    },
355           { "ct",                       "/\bc",             0x00a2    },
356           { "Eu",                       "EUR",              0x20ac    },
357           { "eu",                       "EUR",              0x20ac    },
358           { "Ye",                       "=\bY",             0x00a5    },
359           { "Po",                       "-\bL",             0x00a3    },
360           { "Cs",                       "o\bx",             0x00a4    },
361           { "Fn",                       ",\bf",             0x0192    },
362 
363           /* Units. */
364           { "de",                       "<degree>",         0x00b0    },
365           { "%0",                       "<permille>",       0x2030    },
366           { "fm",                       "\'",               0x2032    },
367           { "sd",                       "''",               0x2033    },
368           { "mc",                       "<micro>",          0x00b5    },
369           { "Of",                       "_\ba",             0x00aa    },
370           { "Om",                       "_\bo",             0x00ba    },
371 
372           /* Greek characters. */
373           { "*A",                       "A",                0x0391    },
374           { "*B",                       "B",                0x0392    },
375           { "*G",                       "<Gamma>",          0x0393    },
376           { "*D",                       "<Delta>",          0x0394    },
377           { "*E",                       "E",                0x0395    },
378           { "*Z",                       "Z",                0x0396    },
379           { "*Y",                       "H",                0x0397    },
380           { "*H",                       "<Theta>",          0x0398    },
381           { "*I",                       "I",                0x0399    },
382           { "*K",                       "K",                0x039a    },
383           { "*L",                       "<Lambda>",         0x039b    },
384           { "*M",                       "M",                0x039c    },
385           { "*N",                       "N",                0x039d    },
386           { "*C",                       "<Xi>",             0x039e    },
387           { "*O",                       "O",                0x039f    },
388           { "*P",                       "<Pi>",             0x03a0    },
389           { "*R",                       "P",                0x03a1    },
390           { "*S",                       "<Sigma>",          0x03a3    },
391           { "*T",                       "T",                0x03a4    },
392           { "*U",                       "Y",                0x03a5    },
393           { "*F",                       "<Phi>",  0x03a6    },
394           { "*X",                       "X",                0x03a7    },
395           { "*Q",                       "<Psi>",  0x03a8    },
396           { "*W",                       "<Omega>",          0x03a9    },
397           { "*a",                       "<alpha>",          0x03b1    },
398           { "*b",                       "<beta>", 0x03b2    },
399           { "*g",                       "<gamma>",          0x03b3    },
400           { "*d",                       "<delta>",          0x03b4    },
401           { "*e",                       "<epsilon>",        0x03b5    },
402           { "*z",                       "<zeta>", 0x03b6    },
403           { "*y",                       "<eta>",  0x03b7    },
404           { "*h",                       "<theta>",          0x03b8    },
405           { "*i",                       "<iota>", 0x03b9    },
406           { "*k",                       "<kappa>",          0x03ba    },
407           { "*l",                       "<lambda>",         0x03bb    },
408           { "*m",                       "<mu>",             0x03bc    },
409           { "*n",                       "<nu>",             0x03bd    },
410           { "*c",                       "<xi>",             0x03be    },
411           { "*o",                       "o",                0x03bf    },
412           { "*p",                       "<pi>",             0x03c0    },
413           { "*r",                       "<rho>",  0x03c1    },
414           { "*s",                       "<sigma>",          0x03c3    },
415           { "*t",                       "<tau>",  0x03c4    },
416           { "*u",                       "<upsilon>",        0x03c5    },
417           { "*f",                       "<phi>",  0x03d5    },
418           { "*x",                       "<chi>",  0x03c7    },
419           { "*q",                       "<psi>",  0x03c8    },
420           { "*w",                       "<omega>",          0x03c9    },
421           { "+h",                       "<theta>",          0x03d1    },
422           { "+f",                       "<phi>",  0x03c6    },
423           { "+p",                       "<pi>",             0x03d6    },
424           { "+e",                       "<epsilon>",        0x03f5    },
425           { "ts",                       "<sigma>",          0x03c2    },
426 };
427 
428 static    struct ohash          mchars;
429 
430 
431 void
mchars_free(void)432 mchars_free(void)
433 {
434 
435           ohash_delete(&mchars);
436 }
437 
438 void
mchars_alloc(void)439 mchars_alloc(void)
440 {
441           size_t                i;
442           unsigned int          slot;
443 
444           mandoc_ohash_init(&mchars, 9, offsetof(struct ln, roffcode));
445           for (i = 0; i < sizeof(lines)/sizeof(lines[0]); i++) {
446                     slot = ohash_qlookup(&mchars, lines[i].roffcode);
447                     assert(ohash_find(&mchars, slot) == NULL);
448                     ohash_insert(&mchars, slot, lines + i);
449           }
450 }
451 
452 int
mchars_spec2cp(const char * p,size_t sz)453 mchars_spec2cp(const char *p, size_t sz)
454 {
455           const struct ln     *ln;
456           const char          *end;
457 
458           end = p + sz;
459           ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
460           return ln != NULL ? ln->unicode : -1;
461 }
462 
463 int
mchars_num2char(const char * p,size_t sz)464 mchars_num2char(const char *p, size_t sz)
465 {
466           int         i;
467 
468           i = mandoc_strntoi(p, sz, 10);
469           return i >= 0 && i < 256 ? i : -1;
470 }
471 
472 int
mchars_num2uc(const char * p,size_t sz)473 mchars_num2uc(const char *p, size_t sz)
474 {
475           int        i;
476 
477           i = mandoc_strntoi(p, sz, 16);
478           assert(i >= 0 && i <= 0x10FFFF);
479           return i;
480 }
481 
482 const char *
mchars_spec2str(const char * p,size_t sz,size_t * rsz)483 mchars_spec2str(const char *p, size_t sz, size_t *rsz)
484 {
485           const struct ln     *ln;
486           const char          *end;
487 
488           end = p + sz;
489           ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
490           if (ln == NULL)
491                     return NULL;
492 
493           *rsz = strlen(ln->ascii);
494           return ln->ascii;
495 }
496 
497 const char *
mchars_uc2str(int uc)498 mchars_uc2str(int uc)
499 {
500           size_t      i;
501 
502           for (i = 0; i < sizeof(lines)/sizeof(lines[0]); i++)
503                     if (uc == lines[i].unicode)
504                               return lines[i].ascii;
505           return "<?>";
506 }
507