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