1 /* $NetBSD: wsfont.c,v 1.77 2021/12/24 18:12:58 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000, 2001, 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: wsfont.c,v 1.77 2021/12/24 18:12:58 jmcneill Exp $"); 34 35 #include "opt_wsfont.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/time.h> 40 #include <sys/malloc.h> 41 #include <sys/queue.h> 42 43 #include <dev/wscons/wsdisplayvar.h> 44 #include <dev/wscons/wsconsio.h> 45 #include <dev/wsfont/wsfont.h> 46 47 #include "wsfont_glue.h" /* NRASOPS_ROTATION */ 48 49 #undef HAVE_FONT 50 51 #ifdef FONT_QVSS8x15 52 #define HAVE_FONT 1 53 #include <dev/wsfont/qvss8x15.h> 54 #endif 55 56 #ifdef FONT_GALLANT12x22 57 #define HAVE_FONT 1 58 #include <dev/wsfont/gallant12x22.h> 59 #endif 60 61 #ifdef FONT_LUCIDA16x29 62 #define HAVE_FONT 1 63 #include <dev/wsfont/lucida16x29.h> 64 #endif 65 66 #ifdef FONT_VT220L8x8 67 #define HAVE_FONT 1 68 #include <dev/wsfont/vt220l8x8.h> 69 #endif 70 71 #ifdef FONT_VT220L8x10 72 #define HAVE_FONT 1 73 #include <dev/wsfont/vt220l8x10.h> 74 #endif 75 76 #ifdef FONT_VT220L8x16 77 #define HAVE_FONT 1 78 #include <dev/wsfont/vt220l8x16.h> 79 #endif 80 81 #ifdef FONT_VT220ISO8x8 82 #define HAVE_FONT 1 83 #include <dev/wsfont/vt220iso8x8.h> 84 #endif 85 86 #ifdef FONT_VT220ISO8x16 87 #define HAVE_FONT 1 88 #include <dev/wsfont/vt220iso8x16.h> 89 #endif 90 91 #ifdef FONT_VT220KOI8x10_KOI8_R 92 #define HAVE_FONT 1 93 #include <dev/wsfont/vt220koi8x10.h> 94 #endif 95 96 #ifdef FONT_VT220KOI8x10_KOI8_U 97 #define HAVE_FONT 1 98 #define KOI8_U 99 #include <dev/wsfont/vt220koi8x10.h> 100 #undef KOI8_U 101 #endif 102 103 #ifdef FONT_SONY8x16 104 #define HAVE_FONT 1 105 #include <dev/wsfont/sony8x16.h> 106 #endif 107 108 #ifdef FONT_SONY12x24 109 #define HAVE_FONT 1 110 #include <dev/wsfont/sony12x24.h> 111 #endif 112 113 #ifdef FONT_OMRON12x20 114 #define HAVE_FONT 1 115 #include <dev/wsfont/omron12x20.h> 116 #endif 117 118 #ifdef FONT_GLASS10x19 119 #define HAVE_FONT 1 120 #include <dev/wsfont/glass10x19.h> 121 #endif 122 123 #ifdef FONT_GLASS10x25 124 #define HAVE_FONT 1 125 #include <dev/wsfont/glass10x25.h> 126 #endif 127 128 #ifdef FONT_DEJAVU_SANS_MONO12x22 129 #define HAVE_FONT 1 130 #include <dev/wsfont/DejaVu_Sans_Mono_12x22.h> 131 #endif 132 133 #ifdef FONT_DROID_SANS_MONO9x18 134 #define HAVE_FONT 1 135 #include <dev/wsfont/Droid_Sans_Mono_9x18.h> 136 #endif 137 138 #ifdef FONT_DROID_SANS_MONO10x20 139 #define HAVE_FONT 1 140 #include <dev/wsfont/Droid_Sans_Mono_10x20.h> 141 #endif 142 143 #ifdef FONT_DROID_SANS_MONO12x22 144 #define HAVE_FONT 1 145 #include <dev/wsfont/Droid_Sans_Mono_12x22.h> 146 #endif 147 148 #ifdef FONT_DROID_SANS_MONO19x36 149 #define HAVE_FONT 1 150 #include <dev/wsfont/Droid_Sans_Mono_19x36.h> 151 #endif 152 153 #ifdef FONT_GO_MONO12x23 154 #define HAVE_FONT 1 155 #include <dev/wsfont/Go_Mono_12x23.h> 156 #endif 157 158 #ifdef FONT_SPLEEN5x8 159 #define HAVE_FONT 1 160 #include <dev/wsfont/spleen5x8.h> 161 #endif 162 163 #ifdef FONT_SPLEEN6x12 164 #define HAVE_FONT 1 165 #include <dev/wsfont/spleen6x12.h> 166 #endif 167 168 #ifdef FONT_SPLEEN8x16 169 #define HAVE_FONT 1 170 #include <dev/wsfont/spleen8x16.h> 171 #endif 172 173 #ifdef FONT_SPLEEN12x24 174 #define HAVE_FONT 1 175 #include <dev/wsfont/spleen12x24.h> 176 #endif 177 178 #ifdef FONT_SPLEEN16x32 179 #define HAVE_FONT 1 180 #include <dev/wsfont/spleen16x32.h> 181 #endif 182 183 #ifdef FONT_SPLEEN32x64 184 #define HAVE_FONT 1 185 #include <dev/wsfont/spleen32x64.h> 186 #endif 187 188 #ifdef FONT_LIBERATION_MONO12x21 189 #define HAVE_FONT 1 190 #include <dev/wsfont/Liberation_Mono_12x21.h> 191 #endif 192 193 #ifdef FONT_BOLD16x32 194 #define HAVE_FONT 1 195 #include <dev/wsfont/bold16x32.h> 196 #endif 197 198 /* Make sure we always have at least one bitmap font. */ 199 #ifndef HAVE_FONT 200 #define HAVE_FONT 1 201 #define FONT_BOLD8x16 1 202 #endif 203 204 #ifdef FONT_BOLD8x16 205 #include <dev/wsfont/bold8x16.h> 206 #endif 207 208 #define WSFONT_IDENT_MASK 0xffffff00 209 #define WSFONT_IDENT_SHIFT 8 210 #define WSFONT_BITO_MASK 0x000000f0 211 #define WSFONT_BITO_SHIFT 4 212 #define WSFONT_BYTEO_MASK 0x0000000f 213 #define WSFONT_BYTEO_SHIFT 0 214 215 #define WSFONT_BUILTIN 0x01 /* In wsfont.c */ 216 #define WSFONT_STATIC 0x02 /* Font structures not malloc()ed */ 217 #define WSFONT_COPY 0x04 /* Copy of existing font in table */ 218 219 /* Placeholder struct used for linked list */ 220 struct font { 221 TAILQ_ENTRY(font) chain; 222 struct wsdisplay_font *font; 223 u_int lockcount; 224 u_int cookie; 225 u_int flags; 226 }; 227 228 /* Our list of built-in fonts */ 229 static struct font builtin_fonts[] = { 230 #ifdef FONT_BOLD8x16 231 { { NULL, NULL }, &bold8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 232 #endif 233 #ifdef FONT_BOLD16x32 234 { { NULL, NULL }, &bold16x32, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 235 #endif 236 #ifdef FONT_GALLANT12x22 237 { { NULL, NULL }, &gallant12x22, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 238 #endif 239 #ifdef FONT_LUCIDA16x29 240 { { NULL, NULL }, &lucida16x29, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 241 #endif 242 #ifdef FONT_QVSS8x15 243 { { NULL, NULL }, &qvss8x15, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 244 #endif 245 #ifdef FONT_VT220L8x8 246 { { NULL, NULL }, &vt220l8x8, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 247 #endif 248 #ifdef FONT_VT220L8x10 249 { { NULL, NULL }, &vt220l8x10, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 250 #endif 251 #ifdef FONT_VT220L8x16 252 { { NULL, NULL }, &vt220l8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 253 #endif 254 #ifdef FONT_VT220ISO8x8 255 { { NULL, NULL }, &vt220iso8x8, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 256 #endif 257 #ifdef FONT_VT220ISO8x16 258 { { NULL, NULL }, &vt220iso8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 259 #endif 260 #ifdef FONT_VT220KOI8x10_KOI8_R 261 { { NULL, NULL }, &vt220kr8x10, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 262 #endif 263 #ifdef FONT_VT220KOI8x10_KOI8_U 264 { { NULL, NULL }, &vt220ku8x10, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 265 #endif 266 #ifdef FONT_SONY8x16 267 { { NULL, NULL }, &sony8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 268 #endif 269 #ifdef FONT_SONY12x24 270 { { NULL, NULL }, &sony12x24, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 271 #endif 272 #ifdef FONT_OMRON12x20 273 { { NULL, NULL }, &omron12x20, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 274 #endif 275 #ifdef FONT_GLASS10x19 276 { { NULL, NULL }, &Glass_TTY_VT220_10x19, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 277 #endif 278 #ifdef FONT_GLASS10x25 279 { { NULL, NULL }, &Glass_TTY_VT220_10x25, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 280 #endif 281 #ifdef FONT_DEJAVU_SANS_MONO12x22 282 { { NULL, NULL }, &DejaVu_Sans_Mono_12x22, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 283 #endif 284 #ifdef FONT_DROID_SANS_MONO9x18 285 { { NULL, NULL }, &Droid_Sans_Mono_9x18, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 286 #endif 287 #ifdef FONT_DROID_SANS_MONO10x20 288 { { NULL, NULL }, &Droid_Sans_Mono_10x20, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 289 #endif 290 #ifdef FONT_DROID_SANS_MONO12x22 291 { { NULL, NULL }, &Droid_Sans_Mono_12x22, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 292 #endif 293 #ifdef FONT_DROID_SANS_MONO19x36 294 { { NULL, NULL }, &Droid_Sans_Mono_19x36, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 295 #endif 296 #ifdef FONT_GO_MONO12x23 297 { { NULL, NULL }, &Go_Mono_12x23, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 298 #endif 299 #ifdef FONT_SPLEEN5x8 300 { { NULL, NULL }, &spleen5x8, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 301 #endif 302 #ifdef FONT_SPLEEN6x12 303 { { NULL, NULL }, &spleen6x12, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 304 #endif 305 #ifdef FONT_SPLEEN8x16 306 { { NULL, NULL }, &spleen8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 307 #endif 308 #ifdef FONT_SPLEEN12x24 309 { { NULL, NULL }, &spleen12x24, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 310 #endif 311 #ifdef FONT_SPLEEN16x32 312 { { NULL, NULL }, &spleen16x32, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 313 #endif 314 #ifdef FONT_SPLEEN32x64 315 { { NULL, NULL }, &spleen32x64, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 316 #endif 317 #ifdef FONT_LIBERATION_MONO12x21 318 { { NULL, NULL }, &Liberation_Mono_12x21, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN }, 319 #endif 320 { { NULL, NULL }, NULL, 0, 0, 0 }, 321 }; 322 323 static TAILQ_HEAD(,font) list; 324 static int ident; 325 326 /* Reverse the bit order in a byte */ 327 static const u_char reverse[256] = { 328 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 329 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 330 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 331 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 332 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 333 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 334 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 335 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 336 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 337 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 338 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 339 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 340 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 341 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 342 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 343 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 344 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 345 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 346 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 347 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 348 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 349 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 350 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 351 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 352 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 353 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 354 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 355 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 356 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 357 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 358 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 359 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 360 }; 361 362 static struct font *wsfont_find0(int, int); 363 static struct font *wsfont_add0(struct wsdisplay_font *, int); 364 static void wsfont_revbit(struct wsdisplay_font *); 365 static void wsfont_revbyte(struct wsdisplay_font *); 366 367 int 368 wsfont_make_cookie(int cident, int bito, int byteo) 369 { 370 371 return ((cident & WSFONT_IDENT_MASK) | 372 (bito << WSFONT_BITO_SHIFT) | 373 (byteo << WSFONT_BYTEO_SHIFT)); 374 } 375 376 static void 377 wsfont_revbit(struct wsdisplay_font *font) 378 { 379 u_char *p, *m; 380 381 p = (u_char *)font->data; 382 m = p + font->stride * font->numchars * font->fontheight; 383 384 for (; p < m; p++) 385 *p = reverse[*p]; 386 } 387 388 static void 389 wsfont_revbyte(struct wsdisplay_font *font) 390 { 391 int x, l, r, nr; 392 u_char *rp; 393 394 if (font->stride == 1) 395 return; 396 397 rp = (u_char *)font->data; 398 nr = font->numchars * font->fontheight; 399 400 while (nr--) { 401 l = 0; 402 r = font->stride - 1; 403 404 while (l < r) { 405 x = rp[l]; 406 rp[l] = rp[r]; 407 rp[r] = x; 408 l++, r--; 409 } 410 411 rp += font->stride; 412 } 413 } 414 415 void 416 wsfont_enum(void (*cb)(const char *, int, int, int)) 417 { 418 struct wsdisplay_font *f; 419 struct font *ent; 420 421 TAILQ_FOREACH(ent, &list, chain) { 422 f = ent->font; 423 cb(f->name, f->fontwidth, f->fontheight, f->stride); 424 } 425 } 426 427 #if NRASOPS_ROTATION > 0 428 429 static struct wsdisplay_font * 430 wsfont_rotate_internal(struct wsdisplay_font *font, int rotate) 431 { 432 struct wsdisplay_font *newfont; 433 char *newname, *newdata; 434 u_char *ch, *newch, *p, *newp; 435 int namelen, newstride, n, h, w; 436 u_char bit; 437 bool alpha = FONT_IS_ALPHA(font), cw = (rotate == WSFONT_ROTATE_CW); 438 439 /* Duplicate the existing font... */ 440 newfont = malloc(sizeof(*font), M_DEVBUF, M_WAITOK); 441 442 *newfont = *font; 443 444 namelen = strlen(font->name) + 4; 445 newname = malloc(namelen, M_DEVBUF, M_WAITOK); 446 strlcpy(newname, font->name, namelen); 447 strlcat(newname, cw ? "cw" : "ccw", namelen); 448 newfont->name = newname; 449 450 /* Allocate a buffer big enough for the rotated font. */ 451 newstride = alpha ? font->fontheight : howmany(font->fontheight, 8); 452 newdata = malloc(newstride * font->fontwidth * font->numchars, 453 M_DEVBUF, M_WAITOK|M_ZERO); 454 455 #define BYTE_OFFSET(x, alpha) ((alpha) ? (x) : (x) / 8) 456 #define BIT_FROM_LEFT(x) __BIT(7 - ((x) % 8)) 457 #define BIT_FROM_RIGHT(x) __BIT((x) % 8) 458 459 /* Rotate the font a pixel at a time. */ 460 for (n = 0; n < font->numchars; n++) { 461 ch = (u_char *)font->data + 462 (n * font->stride * font->fontheight); 463 newch = newdata + 464 (n * newstride * font->fontwidth); 465 for (h = 0; h < font->fontheight; h++) { 466 for (w = 0; w < font->fontwidth; w++) { 467 p = ch + (h * font->stride) + 468 BYTE_OFFSET(w, alpha); 469 if (cw) { 470 /* Rotate clockwise. */ 471 newp = newch + 472 (w * newstride) + 473 (newstride - 1 - 474 BYTE_OFFSET(h, alpha)); 475 bit = BIT_FROM_RIGHT(h); 476 } else { 477 /* Rotate counter-clockwise. */ 478 newp = newch + 479 ((font->fontwidth - 1 - w) * 480 newstride) + 481 BYTE_OFFSET(h, alpha); 482 bit = BIT_FROM_LEFT(h); 483 } 484 if (alpha) { 485 *newp = *p; 486 } else { 487 if (*p & BIT_FROM_LEFT(w)) 488 *newp |= bit; 489 } 490 } 491 } 492 } 493 494 #undef BYTE_OFFSET 495 #undef BIT_FROM_LEFT 496 #undef BIT_FROM_RIGHT 497 498 newfont->data = newdata; 499 500 /* Update font sizes. */ 501 newfont->stride = newstride; 502 newfont->fontwidth = font->fontheight; 503 newfont->fontheight = font->fontwidth; 504 505 if (wsfont_add(newfont, 0) != 0) { 506 /* 507 * If we seem to have rotated this font already, drop the 508 * new one... 509 */ 510 free(newdata, M_DEVBUF); 511 free(newfont, M_DEVBUF); 512 newfont = NULL; 513 } 514 515 return (newfont); 516 } 517 518 int 519 wsfont_rotate(int cookie, int rotate) 520 { 521 int s, ncookie; 522 struct wsdisplay_font *font; 523 struct font *origfont; 524 525 s = splhigh(); 526 origfont = wsfont_find0(cookie, 0xffffffff); 527 splx(s); 528 529 if (origfont == NULL) 530 return (-1); 531 532 switch (rotate) { 533 case WSFONT_ROTATE_CW: 534 case WSFONT_ROTATE_CCW: 535 font = wsfont_rotate_internal(origfont->font, rotate); 536 if (font == NULL) 537 return (-1); 538 break; 539 540 case WSFONT_ROTATE_UD: 541 default: 542 return (-1); 543 } 544 545 ncookie = wsfont_find(font->name, font->fontwidth, font->fontheight, 546 font->stride, 0, 0, WSFONT_FIND_ALL); 547 548 return (ncookie); 549 } 550 551 #endif /* NRASOPS_ROTATION */ 552 553 void 554 wsfont_init(void) 555 { 556 struct font *ent; 557 static int again; 558 int i; 559 560 if (again != 0) 561 return; 562 again = 1; 563 564 TAILQ_INIT(&list); 565 ent = builtin_fonts; 566 567 for (i = 0; builtin_fonts[i].font != NULL; i++, ent++) { 568 ident += (1 << WSFONT_IDENT_SHIFT); 569 ent->cookie = wsfont_make_cookie(ident, 570 ent->font->bitorder, ent->font->byteorder); 571 TAILQ_INSERT_TAIL(&list, ent, chain); 572 } 573 } 574 575 static struct font * 576 wsfont_find0(int cookie, int mask) 577 { 578 struct font *ent; 579 580 TAILQ_FOREACH(ent, &list, chain) { 581 if ((ent->cookie & mask) == (cookie & mask)) 582 return (ent); 583 } 584 585 return (NULL); 586 } 587 588 int 589 wsfont_matches(struct wsdisplay_font *font, const char *name, 590 int width, int height, int stride, int flags) 591 { 592 int score = 20000; 593 594 /* first weed out fonts the caller doesn't claim support for */ 595 if (FONT_IS_ALPHA(font)) { 596 if (flags & WSFONT_PREFER_ALPHA) 597 score++; 598 if ((flags & WSFONT_FIND_ALPHA) == 0) 599 return 0; 600 } else { 601 if ((flags & WSFONT_FIND_BITMAP) == 0) 602 return 0; 603 } 604 605 if (height != 0 && font->fontheight != height) 606 return (0); 607 608 if (width != 0) { 609 if ((flags & WSFONT_FIND_BESTWIDTH) == 0) { 610 if (font->fontwidth != width) 611 return (0); 612 } else { 613 if (font->fontwidth > width) { 614 score -= uimin(font->fontwidth - width, 9999); 615 if ((flags & WSFONT_PREFER_WIDE) == 0) { 616 score -= 10000; 617 } 618 } else { 619 score -= uimin(width - font->fontwidth, 9999); 620 if ((flags & WSFONT_PREFER_WIDE) != 0) { 621 score -= 10000; 622 } 623 } 624 } 625 } 626 627 if (stride != 0 && font->stride != stride) 628 return (0); 629 630 if (name != NULL && strcmp(font->name, name) != 0) 631 return (0); 632 633 return (score); 634 } 635 636 int 637 wsfont_find(const char *name, int width, int height, int stride, int bito, int byteo, int flags) 638 { 639 struct font *ent, *bestent = NULL; 640 int score, bestscore = 0; 641 642 TAILQ_FOREACH(ent, &list, chain) { 643 score = wsfont_matches(ent->font, name, 644 width, height, stride, flags); 645 if (score > bestscore) { 646 bestscore = score; 647 bestent = ent; 648 } 649 } 650 651 if (bestent != NULL) 652 return (wsfont_make_cookie(bestent->cookie, bito, byteo)); 653 654 return (-1); 655 } 656 657 void 658 wsfont_walk(void (*matchfunc)(struct wsdisplay_font *, void *, int), void *cookie) 659 { 660 struct font *ent; 661 662 TAILQ_FOREACH(ent, &list, chain) { 663 matchfunc(ent->font, cookie, ent->cookie); 664 } 665 } 666 667 static struct font * 668 wsfont_add0(struct wsdisplay_font *font, int copy) 669 { 670 struct font *ent; 671 size_t size; 672 673 ent = malloc(sizeof(struct font), M_DEVBUF, M_WAITOK | M_ZERO); 674 675 /* Is this font statically allocated? */ 676 if (!copy) { 677 ent->font = font; 678 ent->flags = WSFONT_STATIC; 679 } else { 680 void *data; 681 char *name; 682 683 ent->font = malloc(sizeof(struct wsdisplay_font), M_DEVBUF, 684 M_WAITOK); 685 memcpy(ent->font, font, sizeof(*ent->font)); 686 687 size = font->fontheight * font->numchars * font->stride; 688 data = malloc(size, M_DEVBUF, M_WAITOK); 689 memcpy(data, font->data, size); 690 ent->font->data = data; 691 692 name = malloc(strlen(font->name) + 1, M_DEVBUF, M_WAITOK); 693 strlcpy(name, font->name, strlen(font->name) + 1); 694 ent->font->name = name; 695 } 696 697 TAILQ_INSERT_TAIL(&list, ent, chain); 698 return (ent); 699 } 700 701 int 702 wsfont_add(struct wsdisplay_font *font, int copy) 703 { 704 struct font *ent; 705 706 /* Don't allow exact duplicates */ 707 if (wsfont_find(font->name, font->fontwidth, font->fontheight, 708 font->stride, 0, 0, WSFONT_FIND_ALL) >= 0) 709 return (EEXIST); 710 711 ent = wsfont_add0(font, copy); 712 713 ident += (1 << WSFONT_IDENT_SHIFT); 714 ent->cookie = wsfont_make_cookie(ident, font->bitorder, 715 font->byteorder); 716 717 return (0); 718 } 719 720 int 721 wsfont_remove(int cookie) 722 { 723 struct font *ent; 724 725 if ((ent = wsfont_find0(cookie, 0xffffffff)) == NULL) 726 return (ENOENT); 727 728 if ((ent->flags & WSFONT_BUILTIN) != 0 || ent->lockcount != 0) 729 return (EBUSY); 730 731 if ((ent->flags & WSFONT_STATIC) == 0) { 732 free(ent->font->data, M_DEVBUF); 733 free(__UNCONST(ent->font->name), M_DEVBUF); /*XXXUNCONST*/ 734 free(ent->font, M_DEVBUF); 735 } 736 737 TAILQ_REMOVE(&list, ent, chain); 738 free(ent, M_DEVBUF); 739 740 return (0); 741 } 742 743 int 744 wsfont_lock(int cookie, struct wsdisplay_font **ptr) 745 { 746 struct font *ent, *neu; 747 int bito, byteo; 748 749 if ((ent = wsfont_find0(cookie, 0xffffffff)) == NULL) { 750 if ((ent = wsfont_find0(cookie, WSFONT_IDENT_MASK)) == NULL) 751 return (ENOENT); 752 753 bito = (cookie & WSFONT_BITO_MASK) >> WSFONT_BITO_SHIFT; 754 byteo = (cookie & WSFONT_BYTEO_MASK) >> WSFONT_BYTEO_SHIFT; 755 756 if (ent->lockcount != 0) { 757 neu = wsfont_add0(ent->font, 1); 758 neu->flags |= WSFONT_COPY; 759 760 aprint_debug("wsfont: font '%s' bito %d byteo %d " 761 "copied to bito %d byteo %d\n", 762 ent->font->name, 763 ent->font->bitorder, ent->font->byteorder, 764 bito, byteo); 765 766 ent = neu; 767 } 768 769 if (bito && bito != ent->font->bitorder) { 770 wsfont_revbit(ent->font); 771 ent->font->bitorder = bito; 772 } 773 774 if (byteo && byteo != ent->font->byteorder) { 775 wsfont_revbyte(ent->font); 776 ent->font->byteorder = byteo; 777 } 778 779 ent->cookie = cookie; 780 } 781 782 ent->lockcount++; 783 *ptr = ent->font; 784 return (0); 785 } 786 787 int 788 wsfont_unlock(int cookie) 789 { 790 struct font *ent; 791 792 if ((ent = wsfont_find0(cookie, 0xffffffff)) == NULL) 793 return (ENOENT); 794 795 if (ent->lockcount == 0) 796 panic("wsfont_unlock: font not locked"); 797 798 if (--ent->lockcount == 0 && (ent->flags & WSFONT_COPY) != 0) 799 wsfont_remove(cookie); 800 801 return (0); 802 } 803 804 /* 805 * Unicode to font encoding mappings 806 */ 807 808 /* 809 * To save memory, font encoding tables use a two level lookup. First the 810 * high byte of the Unicode is used to lookup the level 2 table, then the 811 * low byte indexes that table. Level 2 tables that are not needed are 812 * omitted (NULL), and both level 1 and level 2 tables have base and size 813 * attributes to keep their size down. 814 */ 815 816 struct wsfont_level1_glyphmap { 817 const struct wsfont_level2_glyphmap **level2; 818 int base; /* High byte for first level2 entry */ 819 int size; /* Number of level2 entries */ 820 }; 821 822 struct wsfont_level2_glyphmap { 823 int base; /* Low byte for first character */ 824 int size; /* Number of characters */ 825 const void *chars; /* Pointer to character number entries */ 826 int width; /* Size of each entry in bytes (1,2,4) */ 827 }; 828 829 #define null16 \ 830 NULL, NULL, NULL, NULL, \ 831 NULL, NULL, NULL, NULL, \ 832 NULL, NULL, NULL, NULL, \ 833 NULL, NULL, NULL, NULL 834 835 /* 836 * IBM 437 maps 837 */ 838 839 static const u_int8_t ibm437_chars_0[] = { 840 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 841 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 842 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 843 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 844 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 845 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 846 96, 97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111, 847 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, 848 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 849 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 850 255,173,155,156, 0, 157, 0, 0, 0, 0, 166,174,170, 0, 0, 0, 851 0, 241,253, 0, 0, 0, 0, 249, 0, 0, 167,175,172,171, 0, 168, 852 0, 0, 0, 0, 142,143,146,128, 0, 144, 0, 0, 0, 0, 0, 0, 853 0, 165, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 154, 0, 0, 0, 854 133,160,131, 0, 132,134,145,135,138,130,136,137,141,161,140,139, 855 0, 164,149,162,147, 0, 148,246, 0, 151,163,150,129, 0, 0, 152 856 }; 857 858 static const u_int8_t ibm437_chars_1[] = { 859 159 860 }; 861 862 static const u_int8_t ibm437_chars_3[] = { 863 226, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 864 228, 0, 0, 232, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 224,225, 865 0, 235,238, 0, 0, 0, 0, 0, 0, 230, 0, 0, 0, 227, 0, 0, 866 229,231 867 }; 868 869 static const u_int8_t ibm437_chars_32[] = { 870 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 871 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 872 0, 0, 0, 0, 0, 0, 0, 0, 158 873 }; 874 875 static const u_int8_t ibm437_chars_34[] = { 876 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 877 0, 0, 0, 248,250,251, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 878 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 879 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 880 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 881 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240, 0, 0,243, 882 242 883 }; 884 885 static const u_int8_t ibm437_chars_35[] = { 886 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 887 244,245 888 }; 889 890 static const u_int8_t ibm437_chars_37[] = { 891 196,205,179,186, 0, 0, 0, 0, 0, 0, 0, 0, 218,213,214,201, 892 191,184,183,187,192,212,211,200,217,190,189,188,195,198, 0, 0, 893 199, 0, 0, 204,180,181, 0, 0, 182, 0, 0, 185,194, 0, 0, 209, 894 210, 0, 0, 203,193, 0, 0, 207,208, 0, 0, 202,197, 0, 0, 216, 895 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, 896 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 897 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 898 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 899 223, 0, 0, 0, 220, 0, 0, 0, 219, 0, 0, 0, 221, 0, 0, 0, 900 222,176,177,178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 901 254 902 }; 903 904 static const struct wsfont_level2_glyphmap ibm437_level2_0 = 905 { 0, 256, ibm437_chars_0, 1 }; 906 907 static const struct wsfont_level2_glyphmap ibm437_level2_1 = 908 { 146, 1, ibm437_chars_1, 1 }; 909 910 static const struct wsfont_level2_glyphmap ibm437_level2_3 = 911 { 147, 50, ibm437_chars_3, 1 }; 912 913 static const struct wsfont_level2_glyphmap ibm437_level2_32 = 914 { 127, 41, ibm437_chars_32, 1 }; 915 916 static const struct wsfont_level2_glyphmap ibm437_level2_34 = 917 { 5, 97, ibm437_chars_34, 1 }; 918 919 static const struct wsfont_level2_glyphmap ibm437_level2_35 = 920 { 16, 18, ibm437_chars_35, 1 }; 921 922 static const struct wsfont_level2_glyphmap ibm437_level2_37 = 923 { 0, 161, ibm437_chars_37, 1 }; 924 925 static const struct wsfont_level2_glyphmap *ibm437_level1[] = { 926 &ibm437_level2_0, &ibm437_level2_1, NULL, &ibm437_level2_3, 927 NULL, NULL, NULL, NULL, 928 NULL, NULL, NULL, NULL, 929 NULL, NULL, NULL, NULL, 930 NULL, NULL, NULL, NULL, 931 NULL, NULL, NULL, NULL, 932 NULL, NULL, NULL, NULL, 933 NULL, NULL, NULL, NULL, 934 &ibm437_level2_32, NULL, &ibm437_level2_34, &ibm437_level2_35, 935 NULL, &ibm437_level2_37 936 }; 937 938 /* 939 * ISO-8859-7 maps 940 */ 941 static const u_int8_t iso7_chars_0[] = { 942 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 943 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 944 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 945 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 946 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 947 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 948 96, 97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111, 949 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, 950 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, 951 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, 952 160, 0, 0, 163, 0, 0, 166,167,168,169, 0, 171,172,173, 0, 0, 953 176,177,178,179,180, 0, 0, 183, 0, 0, 0, 187, 0, 189 954 }; 955 956 static const u_int8_t iso7_chars_3[] = { 957 182, 0, 184,185,186, 0, 188, 0, 190,191,192,193,194,195,196,197, 958 198,199,200,201,202,203,204,205,206,207,208,209, 0, 211,212,213, 959 214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229, 960 230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245, 961 246,247,248,249,250,251,252,253,254, 0, 0, 0, 0, 0, 0, 0, 962 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 963 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 181 964 }; 965 966 /* 967 * map all variants of the box drawing characters to the same basic shapes for 968 * now, encoded like this: 969 * 970 * 1 971 * 1 972 * 888 222 973 * 4 974 * 4 975 * 976 * so an upright line would be 0x05 977 */ 978 #define FL |WSFONT_FLAG_OPT 979 static const u_int32_t netbsd_boxes[] = { 980 /*00*/ 0x0a FL, 0x0a FL, 0x05 FL, 0x05 FL, 0x0a FL, 0x0a FL, 0x05 FL, 0x05 FL, 981 /*08*/ 0x0a FL, 0x0a FL, 0x05 FL, 0x05 FL, 0x06 FL, 0x06 FL, 0x06 FL, 0x06 FL, 982 /*10*/ 0x0c FL, 0x0c FL, 0x0c FL, 0x0c FL, 0x03 FL, 0x03 FL, 0x03 FL, 0x03 FL, 983 /*18*/ 0x09 FL, 0x09 FL, 0x09 FL, 0x09 FL, 0x07 FL, 0x07 FL, 0x07 FL, 0x07 FL, 984 /*20*/ 0x07 FL, 0x07 FL, 0x07 FL, 0x07 FL, 0x0d FL, 0x0d FL, 0x0d FL, 0x0d FL, 985 /*28*/ 0x0d FL, 0x0d FL, 0x0d FL, 0x0d FL, 0x0e FL, 0x0e FL, 0x0e FL, 0x0e FL, 986 /*30*/ 0x0e FL, 0x0e FL, 0x0e FL, 0x0e FL, 0x0b FL, 0x0b FL, 0x0b FL, 0x0b FL, 987 /*38*/ 0x0b FL, 0x0b FL, 0x0b FL, 0x0b FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 988 /*40*/ 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 989 /*48*/ 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0a FL, 0x0a FL, 0x05 FL, 0x05 FL, 990 /*50*/ 0x0a FL, 0x05 FL, 0x06 FL, 0x06 FL, 0x06 FL, 0x0c FL, 0x0c FL, 0x0c FL, 991 /*58*/ 0x03 FL, 0x03 FL, 0x03 FL, 0x09 FL, 0x09 FL, 0x09 FL, 0x07 FL, 0x07 FL, 992 /*60*/ 0x07 FL, 0x0d FL, 0x0d FL, 0x0d FL, 0x0e FL, 0x0e FL, 0x0e FL, 0x0b FL, 993 /*68*/ 0x0b FL, 0x0b FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x06 FL, 0x0c FL, 0x09 FL, 994 /*70*/ 0x03 FL, 0 FL, 0 FL, 0 FL, 0x08 FL, 0x01 FL, 0x02 FL, 0x04 FL, 995 /*78*/ 0x08 FL, 0x01 FL, 0x02 FL, 0x04 FL, 0x0a FL, 0x05 FL, 0x0a FL, 0x05 FL 996 }; 997 #undef FL 998 999 static const u_int8_t iso7_chars_32[] = { 1000 175, 0, 0, 0, 0, 162, 0, 161 1001 }; 1002 1003 static const struct wsfont_level2_glyphmap iso7_level2_0 = 1004 { 0, 190, iso7_chars_0, 1 }; 1005 1006 static const struct wsfont_level2_glyphmap iso7_level2_3 = 1007 { 134, 111, iso7_chars_3, 1 }; 1008 1009 static const struct wsfont_level2_glyphmap iso7_level2_32 = 1010 { 20, 8, iso7_chars_32, 1 }; 1011 1012 static const struct wsfont_level2_glyphmap netbsd_box_drawing = 1013 { 0, 128, netbsd_boxes, 4 }; 1014 1015 static const struct wsfont_level2_glyphmap *iso7_level1[] = { 1016 &iso7_level2_0, NULL, NULL, &iso7_level2_3, 1017 NULL, NULL, NULL, NULL, 1018 NULL, NULL, NULL, NULL, 1019 NULL, NULL, NULL, NULL, 1020 NULL, NULL, NULL, NULL, 1021 NULL, NULL, NULL, NULL, 1022 NULL, NULL, NULL, NULL, 1023 NULL, NULL, NULL, NULL, 1024 &iso7_level2_32, NULL, NULL, NULL, 1025 NULL, &netbsd_box_drawing 1026 }; 1027 1028 static const struct wsfont_level2_glyphmap *iso_level1[] = { 1029 NULL, NULL, NULL, NULL, 1030 NULL, NULL, NULL, NULL, 1031 NULL, NULL, NULL, NULL, 1032 NULL, NULL, NULL, NULL, 1033 NULL, NULL, NULL, NULL, 1034 NULL, NULL, NULL, NULL, 1035 NULL, NULL, NULL, NULL, 1036 NULL, NULL, NULL, NULL, 1037 NULL, NULL, NULL, NULL, 1038 NULL, &netbsd_box_drawing 1039 }; 1040 1041 static const struct wsfont_level1_glyphmap encodings[] = { 1042 { iso_level1, 0, 0x26 }, /* WSDISPLAY_FONTENC_ISO */ 1043 { ibm437_level1, 0, 38 }, /* WSDISPLAY_FONTENC_IBM */ 1044 { NULL, 0, 0 }, /* WSDISPLAY_FONTENC_PCVT */ 1045 { iso7_level1, 0, 0x26 }, /* WSDISPLAY_FONTENC_ISO7 */ 1046 }; 1047 1048 #define MAX_ENCODING (sizeof(encodings) / sizeof(encodings[0])) 1049 1050 /* 1051 * Remap Unicode character to glyph 1052 */ 1053 int 1054 wsfont_map_unichar(struct wsdisplay_font *font, int c) 1055 { 1056 const struct wsfont_level1_glyphmap *map1; 1057 const struct wsfont_level2_glyphmap *map2; 1058 int hi, lo; 1059 1060 if (font->encoding < 0 || font->encoding >= MAX_ENCODING) 1061 return (-1); 1062 1063 hi = (c >> 8); 1064 lo = c & 255; 1065 map1 = &encodings[font->encoding]; 1066 1067 if (hi < map1->base || hi >= map1->base + map1->size) 1068 return (-1); 1069 1070 map2 = map1->level2[hi - map1->base]; 1071 1072 /* so we don't need an identical level 2 table for hi == 0 */ 1073 if (hi == 0 && font->encoding == WSDISPLAY_FONTENC_ISO) 1074 return lo; 1075 1076 if (map2 == NULL || lo < map2->base || lo >= map2->base + map2->size) 1077 return (-1); 1078 1079 lo -= map2->base; 1080 1081 switch(map2->width) { 1082 case 1: 1083 c = (((const u_int8_t *)map2->chars)[lo]); 1084 break; 1085 case 2: 1086 c = (((const u_int16_t *)map2->chars)[lo]); 1087 break; 1088 case 4: 1089 c = (((const u_int32_t *)map2->chars)[lo]); 1090 break; 1091 } 1092 1093 if (c == 0 && lo != 0) 1094 return (-1); 1095 1096 return (c); 1097 } 1098