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