added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / arch / common / grub2 / font / manager.c
blob8d5f0213ba9392b46df582dd0db6c8fe0184438c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2003,2005,2006,2007 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/file.h>
20 #include <grub/misc.h>
21 #include <grub/dl.h>
22 #include <grub/normal.h>
23 #include <grub/types.h>
24 #include <grub/mm.h>
25 #include <grub/font.h>
27 struct entry
29 grub_uint32_t code;
30 grub_uint32_t offset;
33 struct font
35 struct font *next;
36 grub_file_t file;
37 grub_uint32_t num;
38 struct entry table[0];
41 static struct font *font_list;
43 static int
44 add_font (const char *filename)
46 grub_file_t file = 0;
47 char magic[4];
48 grub_uint32_t num, i;
49 struct font *font = 0;
51 file = grub_file_open (filename);
52 if (! file)
53 goto fail;
55 if (grub_file_read (file, magic, 4) != 4)
56 goto fail;
58 if (grub_memcmp (magic, GRUB_FONT_MAGIC, 4) != 0)
60 grub_error (GRUB_ERR_BAD_FONT, "invalid font magic");
61 goto fail;
64 if (grub_file_read (file, (char *) &num, 4) != 4)
65 goto fail;
67 num = grub_le_to_cpu32 (num);
68 font = (struct font *) grub_malloc (sizeof (struct font)
69 + sizeof (struct entry) * num);
70 if (! font)
71 goto fail;
73 font->file = file;
74 font->num = num;
76 for (i = 0; i < num; i++)
78 grub_uint32_t code, offset;
80 if (grub_file_read (file, (char *) &code, 4) != 4)
81 goto fail;
83 if (grub_file_read (file, (char *) &offset, 4) != 4)
84 goto fail;
86 font->table[i].code = grub_le_to_cpu32 (code);
87 font->table[i].offset = grub_le_to_cpu32 (offset);
90 font->next = font_list;
91 font_list = font;
93 return 1;
95 fail:
96 if (font)
97 grub_free (font);
99 if (file)
100 grub_file_close (file);
102 return 0;
105 static void
106 remove_font (struct font *font)
108 struct font **p, *q;
110 for (p = &font_list, q = *p; q; p = &(q->next), q = q->next)
111 if (q == font)
113 *p = q->next;
115 grub_file_close (font->file);
116 grub_free (font);
118 break;
122 /* Return the offset of the glyph corresponding to the codepoint CODE
123 in the font FONT. If no found, return zero. */
124 static grub_uint32_t
125 find_glyph (const struct font *font, grub_uint32_t code)
127 grub_uint32_t start = 0;
128 grub_uint32_t end = font->num - 1;
129 const struct entry *table = font->table;
131 /* This shouldn't happen. */
132 if (font->num == 0)
133 return 0;
135 /* Do a binary search. */
136 while (start <= end)
138 grub_uint32_t i = (start + end) / 2;
140 if (table[i].code < code)
141 start = i + 1;
142 else if (table[i].code > code)
143 end = i - 1;
144 else
145 return table[i].offset;
148 return 0;
151 /* Set the glyph to something stupid. */
152 static void
153 fill_with_default_glyph (grub_font_glyph_t glyph)
155 unsigned i;
157 for (i = 0; i < 16; i++)
158 glyph->bitmap[i] = (i & 1) ? 0x55 : 0xaa;
160 glyph->char_width = 1;
161 glyph->width = glyph->char_width * 8;
162 glyph->height = 16;
163 glyph->baseline = (16 * 3) / 4;
166 /* Get a glyph corresponding to the codepoint CODE. Always fill glyph
167 information with something, even if no glyph is found. */
169 grub_font_get_glyph (grub_uint32_t code,
170 grub_font_glyph_t glyph)
172 struct font *font;
173 grub_uint8_t bitmap[32];
175 /* FIXME: It is necessary to cache glyphs! */
177 restart:
178 for (font = font_list; font; font = font->next)
180 grub_uint32_t offset;
182 offset = find_glyph (font, code);
183 if (offset)
185 grub_uint32_t w;
186 int len;
188 /* Make sure we can find glyphs for error messages. Push active
189 error message to error stack and reset error message. */
190 grub_error_push ();
192 grub_file_seek (font->file, offset);
193 if ((len = grub_file_read (font->file, (char *) &w, sizeof (w)))
194 != sizeof (w))
196 remove_font (font);
197 goto restart;
200 w = grub_le_to_cpu32 (w);
201 if (w != 1 && w != 2)
203 /* grub_error (GRUB_ERR_BAD_FONT, "invalid width"); */
204 remove_font (font);
205 goto restart;
208 if (grub_file_read (font->file, (char *) bitmap, w * 16)
209 != (grub_ssize_t) w * 16)
211 remove_font (font);
212 goto restart;
215 /* Fill glyph with information. */
216 grub_memcpy (glyph->bitmap, bitmap, w * 16);
218 glyph->char_width = w;
219 glyph->width = glyph->char_width * 8;
220 glyph->height = 16;
221 glyph->baseline = (16 * 3) / 4;
223 /* Restore old error message. */
224 grub_error_pop ();
226 return 1;
230 /* Uggh... No font was found. */
231 fill_with_default_glyph (glyph);
232 return 0;
235 static grub_err_t
236 font_command (struct grub_arg_list *state __attribute__ ((unused)),
237 int argc __attribute__ ((unused)),
238 char **args __attribute__ ((unused)))
240 if (argc == 0)
241 return grub_error (GRUB_ERR_BAD_ARGUMENT, "no font specified");
243 while (argc--)
244 if (! add_font (*args++))
245 return 1;
247 return 0;
250 GRUB_MOD_INIT(font_manager)
252 grub_register_command ("font", font_command, GRUB_COMMAND_FLAG_BOTH,
253 "font FILE...",
254 "Specify one or more font files to display.", 0);
257 GRUB_MOD_FINI(font_manager)
259 grub_unregister_command ("font");