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