~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to gfxmenu/theme_loader.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* theme_loader.c - Theme file loader for gfxmenu.  */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2008  Free Software Foundation, Inc.
5
 
 *
6
 
 *  GRUB is free software: you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation, either version 3 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  GRUB is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18
 
 */
19
 
 
20
 
#include <grub/types.h>
21
 
#include <grub/file.h>
22
 
#include <grub/misc.h>
23
 
#include <grub/mm.h>
24
 
#include <grub/err.h>
25
 
#include <grub/dl.h>
26
 
#include <grub/video.h>
27
 
#include <grub/gui_string_util.h>
28
 
#include <grub/bitmap.h>
29
 
#include <grub/bitmap_scale.h>
30
 
#include <grub/gfxwidgets.h>
31
 
#include <grub/gfxmenu_view.h>
32
 
#include <grub/gui.h>
33
 
 
34
 
/* Construct a new box widget using ABSPATTERN to find the pixmap files for
35
 
   it, storing the new box instance at *BOXPTR.
36
 
   PATTERN should be of the form: "(hd0,0)/somewhere/style*.png".
37
 
   The '*' then gets substituted with the various pixmap names that the
38
 
   box uses.  */
39
 
static grub_err_t
40
 
recreate_box_absolute (grub_gfxmenu_box_t *boxptr, const char *abspattern)
41
 
{
42
 
  char *prefix;
43
 
  char *suffix;
44
 
  char *star;
45
 
  grub_gfxmenu_box_t box;
46
 
 
47
 
  star = grub_strchr (abspattern, '*');
48
 
  if (! star)
49
 
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
50
 
                       "missing `*' in box pixmap pattern `%s'", abspattern);
51
 
 
52
 
  /* Prefix:  Get the part before the '*'.  */
53
 
  prefix = grub_malloc (star - abspattern + 1);
54
 
  if (! prefix)
55
 
    return grub_errno;
56
 
 
57
 
  grub_memcpy (prefix, abspattern, star - abspattern);
58
 
  prefix[star - abspattern] = '\0';
59
 
 
60
 
  /* Suffix:  Everything after the '*' is the suffix.  */
61
 
  suffix = star + 1;
62
 
 
63
 
  box = grub_gfxmenu_create_box (prefix, suffix);
64
 
  grub_free (prefix);
65
 
  if (! box)
66
 
    return grub_errno;
67
 
 
68
 
  if (*boxptr)
69
 
    (*boxptr)->destroy (*boxptr);
70
 
  *boxptr = box;
71
 
  return grub_errno;
72
 
}
73
 
 
74
 
 
75
 
/* Construct a new box widget using PATTERN to find the pixmap files for it,
76
 
   storing the new widget at *BOXPTR.  PATTERN should be of the form:
77
 
   "somewhere/style*.png".  The '*' then gets substituted with the various
78
 
   pixmap names that the widget uses.
79
 
 
80
 
   Important!  The value of *BOXPTR must be initialized!  It must either
81
 
   (1) Be 0 (a NULL pointer), or
82
 
   (2) Be a pointer to a valid 'grub_gfxmenu_box_t' instance.
83
 
   In this case, the previous instance is destroyed.  */
84
 
grub_err_t
85
 
grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr,
86
 
                       const char *pattern, const char *theme_dir)
87
 
{
88
 
  char *abspattern;
89
 
 
90
 
  /* Check arguments.  */
91
 
  if (! pattern)
92
 
    {
93
 
      /* If no pixmap pattern is given, then just create an empty box.  */
94
 
      if (*boxptr)
95
 
        (*boxptr)->destroy (*boxptr);
96
 
      *boxptr = grub_gfxmenu_create_box (0, 0);
97
 
      return grub_errno;
98
 
    }
99
 
 
100
 
  if (! theme_dir)
101
 
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
102
 
                       "styled box missing theme directory");
103
 
 
104
 
  /* Resolve to an absolute path.  */
105
 
  abspattern = grub_resolve_relative_path (theme_dir, pattern);
106
 
  if (! abspattern)
107
 
    return grub_errno;
108
 
 
109
 
  /* Create the box.  */
110
 
  recreate_box_absolute (boxptr, abspattern);
111
 
  grub_free (abspattern);
112
 
  return grub_errno;
113
 
}
114
 
 
115
 
/* Set the specified property NAME on the view to the given string VALUE.
116
 
   The caller is responsible for the lifetimes of NAME and VALUE.  */
117
 
static grub_err_t
118
 
theme_set_string (grub_gfxmenu_view_t view,
119
 
                  const char *name,
120
 
                  const char *value,
121
 
                  const char *theme_dir,
122
 
                  const char *filename,
123
 
                  int line_num,
124
 
                  int col_num)
125
 
{
126
 
  if (! grub_strcmp ("title-font", name))
127
 
    view->title_font = grub_font_get (value);
128
 
  else if (! grub_strcmp ("message-font", name))
129
 
    view->message_font = grub_font_get (value);
130
 
  else if (! grub_strcmp ("terminal-font", name))
131
 
    {
132
 
      grub_free (view->terminal_font_name);
133
 
      view->terminal_font_name = grub_strdup (value);
134
 
      if (! view->terminal_font_name)
135
 
        return grub_errno;
136
 
    }
137
 
  else if (! grub_strcmp ("title-color", name))
138
 
    grub_gui_parse_color (value, &view->title_color);
139
 
  else if (! grub_strcmp ("message-color", name))
140
 
    grub_gui_parse_color (value, &view->message_color);
141
 
  else if (! grub_strcmp ("message-bg-color", name))
142
 
    grub_gui_parse_color (value, &view->message_bg_color);
143
 
  else if (! grub_strcmp ("desktop-image", name))
144
 
    {
145
 
      struct grub_video_bitmap *raw_bitmap;
146
 
      struct grub_video_bitmap *scaled_bitmap;
147
 
      char *path;
148
 
      path = grub_resolve_relative_path (theme_dir, value);
149
 
      if (! path)
150
 
        return grub_errno;
151
 
      if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE)
152
 
        {
153
 
          grub_free (path);
154
 
          return grub_errno;
155
 
        }
156
 
      grub_free(path);
157
 
      grub_video_bitmap_create_scaled (&scaled_bitmap,
158
 
                                       view->screen.width,
159
 
                                       view->screen.height,
160
 
                                       raw_bitmap,
161
 
                                       GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
162
 
      grub_video_bitmap_destroy (raw_bitmap);
163
 
      if (! scaled_bitmap)
164
 
        {
165
 
          grub_error_push ();
166
 
          return grub_error (grub_errno, "error scaling desktop image");
167
 
        }
168
 
 
169
 
      grub_video_bitmap_destroy (view->desktop_image);
170
 
      view->desktop_image = scaled_bitmap;
171
 
    }
172
 
  else if (! grub_strcmp ("desktop-color", name))
173
 
     grub_gui_parse_color (value, &view->desktop_color);
174
 
  else if (! grub_strcmp ("terminal-box", name))
175
 
    {
176
 
        grub_err_t err;
177
 
        err = grub_gui_recreate_box (&view->terminal_box, value, theme_dir);
178
 
        if (err != GRUB_ERR_NONE)
179
 
          return err;
180
 
    }
181
 
  else if (! grub_strcmp ("title-text", name))
182
 
    {
183
 
      grub_free (view->title_text);
184
 
      view->title_text = grub_strdup (value);
185
 
      if (! view->title_text)
186
 
        return grub_errno;
187
 
    }
188
 
  else
189
 
    {
190
 
      return grub_error (GRUB_ERR_BAD_ARGUMENT,
191
 
                         "%s:%d:%d unknown property `%s'",
192
 
                         filename, line_num, col_num, name);
193
 
    }
194
 
  return grub_errno;
195
 
}
196
 
 
197
 
struct parsebuf
198
 
{
199
 
  char *buf;
200
 
  int pos;
201
 
  int len;
202
 
  int line_num;
203
 
  int col_num;
204
 
  const char *filename;
205
 
  char *theme_dir;
206
 
  grub_gfxmenu_view_t view;
207
 
};
208
 
 
209
 
static int
210
 
has_more (struct parsebuf *p)
211
 
{
212
 
  return p->pos < p->len;
213
 
}
214
 
 
215
 
static int
216
 
read_char (struct parsebuf *p)
217
 
{
218
 
  if (has_more (p))
219
 
    {
220
 
      char c;
221
 
      c = p->buf[p->pos++];
222
 
      if (c == '\n')
223
 
        {
224
 
          p->line_num++;
225
 
          p->col_num = 1;
226
 
        }
227
 
      else
228
 
        {
229
 
          p->col_num++;
230
 
        }
231
 
      return c;
232
 
    }
233
 
  else
234
 
    return -1;
235
 
}
236
 
 
237
 
static int
238
 
peek_char (struct parsebuf *p)
239
 
{
240
 
  if (has_more (p))
241
 
    return p->buf[p->pos];
242
 
  else
243
 
    return -1;
244
 
}
245
 
 
246
 
static int
247
 
is_whitespace (char c)
248
 
{
249
 
  return (c == ' '
250
 
          || c == '\t'
251
 
          || c == '\r'
252
 
          || c == '\n'
253
 
          || c == '\f');
254
 
}
255
 
 
256
 
static void
257
 
skip_whitespace (struct parsebuf *p)
258
 
{
259
 
  while (has_more (p) && is_whitespace(peek_char (p)))
260
 
    read_char (p);
261
 
}
262
 
 
263
 
static void
264
 
advance_to_next_line (struct parsebuf *p)
265
 
{
266
 
  int c;
267
 
 
268
 
  /* Eat characters up to the newline.  */
269
 
  do
270
 
    {
271
 
      c = read_char (p);
272
 
    }
273
 
  while (c != -1 && c != '\n');
274
 
}
275
 
 
276
 
static int
277
 
is_identifier_char (int c)
278
 
{
279
 
  return (c != -1
280
 
          && (grub_isalpha(c)
281
 
              || grub_isdigit(c)
282
 
              || c == '_'
283
 
              || c == '-'));
284
 
}
285
 
 
286
 
static char *
287
 
read_identifier (struct parsebuf *p)
288
 
{
289
 
  /* Index of the first character of the identifier in p->buf.  */
290
 
  int start;
291
 
  /* Next index after the last character of the identifer in p->buf.  */
292
 
  int end;
293
 
 
294
 
  skip_whitespace (p);
295
 
 
296
 
  /* Capture the start of the identifier.  */
297
 
  start = p->pos;
298
 
 
299
 
  /* Scan for the end.  */
300
 
  while (is_identifier_char (peek_char (p)))
301
 
    read_char (p);
302
 
  end = p->pos;
303
 
 
304
 
  if (end - start < 1)
305
 
    return 0;
306
 
 
307
 
  return grub_new_substring (p->buf, start, end);
308
 
}
309
 
 
310
 
static char *
311
 
read_expression (struct parsebuf *p)
312
 
{
313
 
  int start;
314
 
  int end;
315
 
 
316
 
  skip_whitespace (p);
317
 
  if (peek_char (p) == '"')
318
 
    {
319
 
      /* Read as a quoted string.  
320
 
         The quotation marks are not included in the expression value.  */
321
 
      /* Skip opening quotation mark.  */
322
 
      read_char (p);
323
 
      start = p->pos;
324
 
      while (has_more (p) && peek_char (p) != '"')
325
 
        read_char (p);
326
 
      end = p->pos;
327
 
      /* Skip the terminating quotation mark.  */
328
 
      read_char (p);
329
 
    }
330
 
  else if (peek_char (p) == '(')
331
 
    {
332
 
      /* Read as a parenthesized string -- for tuples/coordinates.  */
333
 
      /* The parentheses are included in the expression value.  */
334
 
      int c;
335
 
 
336
 
      start = p->pos;
337
 
      do
338
 
        {
339
 
          c = read_char (p);
340
 
        }
341
 
      while (c != -1 && c != ')');
342
 
      end = p->pos;
343
 
    }
344
 
  else if (has_more (p))
345
 
    {
346
 
      /* Read as a single word -- for numeric values or words without
347
 
         whitespace.  */
348
 
      start = p->pos;
349
 
      while (has_more (p) && ! is_whitespace (peek_char (p)))
350
 
        read_char (p);
351
 
      end = p->pos;
352
 
    }
353
 
  else
354
 
    {
355
 
      /* The end of the theme file has been reached.  */
356
 
      grub_error (GRUB_ERR_IO, "%s:%d:%d expression expected in theme file",
357
 
                  p->filename, p->line_num, p->col_num);
358
 
      return 0;
359
 
    }
360
 
 
361
 
  return grub_new_substring (p->buf, start, end);
362
 
}
363
 
 
364
 
static grub_err_t
365
 
parse_proportional_spec (char *value, signed *abs, grub_fixed_signed_t *prop)
366
 
{
367
 
  signed num;
368
 
  char *ptr;
369
 
  int sig = 0;
370
 
  *abs = 0;
371
 
  *prop = 0;
372
 
  ptr = value;
373
 
  while (*ptr)
374
 
    {
375
 
      sig = 0;
376
 
 
377
 
      while (*ptr == '-' || *ptr == '+')
378
 
        {
379
 
          if (*ptr == '-')
380
 
            sig = !sig;
381
 
          ptr++;
382
 
        }
383
 
 
384
 
      num = grub_strtoul (ptr, &ptr, 0);
385
 
      if (grub_errno)
386
 
        return grub_errno;
387
 
      if (sig)
388
 
        num = -num;
389
 
      if (*ptr == '%')
390
 
        {
391
 
          *prop += grub_fixed_fsf_divide (grub_signed_to_fixed (num), 100);
392
 
          ptr++;
393
 
        }
394
 
      else
395
 
        *abs += num;
396
 
    }
397
 
  return GRUB_ERR_NONE;
398
 
}
399
 
 
400
 
 
401
 
/* Read a GUI object specification from the theme file.
402
 
   Any components created will be added to the GUI container PARENT.  */
403
 
static grub_err_t
404
 
read_object (struct parsebuf *p, grub_gui_container_t parent)
405
 
{
406
 
  grub_video_rect_t bounds;
407
 
 
408
 
  char *name;
409
 
  name = read_identifier (p);
410
 
  if (! name)
411
 
    goto cleanup;
412
 
 
413
 
  grub_gui_component_t component = 0;
414
 
  if (grub_strcmp (name, "label") == 0)
415
 
    {
416
 
      component = grub_gui_label_new ();
417
 
    }
418
 
  else if (grub_strcmp (name, "image") == 0)
419
 
    {
420
 
      component = grub_gui_image_new ();
421
 
    }
422
 
  else if (grub_strcmp (name, "vbox") == 0)
423
 
    {
424
 
      component = (grub_gui_component_t) grub_gui_vbox_new ();
425
 
    }
426
 
  else if (grub_strcmp (name, "hbox") == 0)
427
 
    {
428
 
      component = (grub_gui_component_t) grub_gui_hbox_new ();
429
 
    }
430
 
  else if (grub_strcmp (name, "canvas") == 0)
431
 
    {
432
 
      component = (grub_gui_component_t) grub_gui_canvas_new ();
433
 
    }
434
 
  else if (grub_strcmp (name, "progress_bar") == 0)
435
 
    {
436
 
      component = grub_gui_progress_bar_new ();
437
 
    }
438
 
  else if (grub_strcmp (name, "circular_progress") == 0)
439
 
    {
440
 
      component = grub_gui_circular_progress_new ();
441
 
    }
442
 
  else if (grub_strcmp (name, "boot_menu") == 0)
443
 
    {
444
 
      component = grub_gui_list_new ();
445
 
    }
446
 
  else
447
 
    {
448
 
      /* Unknown type.  */
449
 
      grub_error (GRUB_ERR_IO, "%s:%d:%d unknown object type `%s'",
450
 
                  p->filename, p->line_num, p->col_num, name);
451
 
      goto cleanup;
452
 
    }
453
 
 
454
 
  if (! component)
455
 
    goto cleanup;
456
 
 
457
 
  /* Inform the component about the theme so it can find its resources.  */
458
 
  component->ops->set_property (component, "theme_dir", p->theme_dir);
459
 
  component->ops->set_property (component, "theme_path", p->filename);
460
 
 
461
 
  /* Add the component as a child of PARENT.  */
462
 
  bounds.x = 0;
463
 
  bounds.y = 0;
464
 
  bounds.width = -1;
465
 
  bounds.height = -1;
466
 
  component->ops->set_bounds (component, &bounds);
467
 
  parent->ops->add (parent, component);
468
 
 
469
 
  skip_whitespace (p);
470
 
  if (read_char (p) != '{')
471
 
    {
472
 
      grub_error (GRUB_ERR_IO,
473
 
                  "%s:%d:%d expected `{' after object type name `%s'",
474
 
                  p->filename, p->line_num, p->col_num, name);
475
 
      goto cleanup;
476
 
    }
477
 
 
478
 
  while (has_more (p))
479
 
    {
480
 
      skip_whitespace (p);
481
 
 
482
 
      /* Check whether the end has been encountered.  */
483
 
      if (peek_char (p) == '}')
484
 
        {
485
 
          /* Skip the closing brace.  */
486
 
          read_char (p);
487
 
          break;
488
 
        }
489
 
 
490
 
      if (peek_char (p) == '#')
491
 
        {
492
 
          /* Skip comments.  */
493
 
          advance_to_next_line (p);
494
 
          continue;
495
 
        }
496
 
 
497
 
      if (peek_char (p) == '+')
498
 
        {
499
 
          /* Skip the '+'.  */
500
 
          read_char (p);
501
 
 
502
 
          /* Check whether this component is a container.  */
503
 
          if (component->ops->is_instance (component, "container"))
504
 
            {
505
 
              /* Read the sub-object recursively and add it as a child.  */
506
 
              if (read_object (p, (grub_gui_container_t) component) != 0)
507
 
                goto cleanup;
508
 
              /* After reading the sub-object, resume parsing, expecting
509
 
                 another property assignment or sub-object definition.  */
510
 
              continue;
511
 
            }
512
 
          else
513
 
            {
514
 
              grub_error (GRUB_ERR_IO,
515
 
                          "%s:%d:%d attempted to add object to non-container",
516
 
                          p->filename, p->line_num, p->col_num);
517
 
              goto cleanup;
518
 
            }
519
 
        }
520
 
 
521
 
      char *property;
522
 
      property = read_identifier (p);
523
 
      if (! property)
524
 
        {
525
 
          grub_error (GRUB_ERR_IO, "%s:%d:%d identifier expected in theme file",
526
 
                      p->filename, p->line_num, p->col_num);
527
 
          goto cleanup;
528
 
        }
529
 
 
530
 
      skip_whitespace (p);
531
 
      if (read_char (p) != '=')
532
 
        {
533
 
          grub_error (GRUB_ERR_IO,
534
 
                      "%s:%d:%d expected `=' after property name `%s'",
535
 
                      p->filename, p->line_num, p->col_num, property);
536
 
          grub_free (property);
537
 
          goto cleanup;
538
 
        }
539
 
      skip_whitespace (p);
540
 
 
541
 
      char *value;
542
 
      value = read_expression (p);
543
 
      if (! value)
544
 
        {
545
 
          grub_free (property);
546
 
          goto cleanup;
547
 
        }
548
 
 
549
 
      /* Handle the property value.  */
550
 
      if (grub_strcmp (property, "left") == 0)
551
 
        parse_proportional_spec (value, &component->x, &component->xfrac);
552
 
      else if (grub_strcmp (property, "top") == 0)
553
 
        parse_proportional_spec (value, &component->y, &component->yfrac);
554
 
      else if (grub_strcmp (property, "width") == 0)
555
 
        parse_proportional_spec (value, &component->w, &component->wfrac);
556
 
      else if (grub_strcmp (property, "height") == 0)
557
 
        parse_proportional_spec (value, &component->h, &component->hfrac);
558
 
      else
559
 
        /* General property handling.  */
560
 
        component->ops->set_property (component, property, value);
561
 
 
562
 
      grub_free (value);
563
 
      grub_free (property);
564
 
      if (grub_errno != GRUB_ERR_NONE)
565
 
        goto cleanup;
566
 
    }
567
 
 
568
 
cleanup:
569
 
  grub_free (name);
570
 
  return grub_errno;
571
 
}
572
 
 
573
 
static grub_err_t
574
 
read_property (struct parsebuf *p)
575
 
{
576
 
  char *name;
577
 
 
578
 
  /* Read the property name.  */
579
 
  name = read_identifier (p);
580
 
  if (! name)
581
 
    {
582
 
      advance_to_next_line (p);
583
 
      return grub_errno;
584
 
    }
585
 
 
586
 
  /* Skip whitespace before separator.  */
587
 
  skip_whitespace (p);
588
 
 
589
 
  /* Read separator.  */
590
 
  if (read_char (p) != ':')
591
 
    {
592
 
      grub_error (GRUB_ERR_IO,
593
 
                  "%s:%d:%d missing separator after property name `%s'",
594
 
                  p->filename, p->line_num, p->col_num, name);
595
 
      goto done;
596
 
    }
597
 
 
598
 
  /* Skip whitespace after separator.  */
599
 
  skip_whitespace (p);
600
 
 
601
 
  /* Get the value based on its type.  */
602
 
  if (peek_char (p) == '"')
603
 
    {
604
 
      /* String value (e.g., '"My string"').  */
605
 
      char *value = read_expression (p);
606
 
      if (! value)
607
 
        {
608
 
          grub_error (GRUB_ERR_IO, "%s:%d:%d missing property value",
609
 
                      p->filename, p->line_num, p->col_num);
610
 
          goto done;
611
 
        }
612
 
      /* If theme_set_string results in an error, grub_errno will be returned
613
 
         below.  */
614
 
      theme_set_string (p->view, name, value, p->theme_dir,
615
 
                        p->filename, p->line_num, p->col_num);
616
 
      grub_free (value);
617
 
    }
618
 
  else
619
 
    {
620
 
      grub_error (GRUB_ERR_IO,
621
 
                  "%s:%d:%d property value invalid; "
622
 
                  "enclose literal values in quotes (\")",
623
 
                  p->filename, p->line_num, p->col_num);
624
 
      goto done;
625
 
    }
626
 
 
627
 
done:
628
 
  grub_free (name);
629
 
  return grub_errno;
630
 
}
631
 
 
632
 
/* Set properties on the view based on settings from the specified
633
 
   theme file.  */
634
 
grub_err_t
635
 
grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path)
636
 
{
637
 
  grub_file_t file;
638
 
  struct parsebuf p;
639
 
 
640
 
  p.view = view;
641
 
  p.theme_dir = grub_get_dirname (theme_path);
642
 
 
643
 
  file = grub_file_open (theme_path);
644
 
  if (! file)
645
 
    {
646
 
      grub_free (p.theme_dir);
647
 
      return grub_errno;
648
 
    }
649
 
 
650
 
  p.len = grub_file_size (file);
651
 
  p.buf = grub_malloc (p.len);
652
 
  p.pos = 0;
653
 
  p.line_num = 1;
654
 
  p.col_num = 1;
655
 
  p.filename = theme_path;
656
 
  if (! p.buf)
657
 
    {
658
 
      grub_file_close (file);
659
 
      grub_free (p.theme_dir);
660
 
      return grub_errno;
661
 
    }
662
 
  if (grub_file_read (file, p.buf, p.len) != p.len)
663
 
    {
664
 
      grub_free (p.buf);
665
 
      grub_file_close (file);
666
 
      grub_free (p.theme_dir);
667
 
      return grub_errno;
668
 
    }
669
 
 
670
 
  if (view->canvas)
671
 
    view->canvas->component.ops->destroy (view->canvas);
672
 
 
673
 
  view->canvas = grub_gui_canvas_new ();
674
 
  ((grub_gui_component_t) view->canvas)
675
 
    ->ops->set_bounds ((grub_gui_component_t) view->canvas,
676
 
                       &view->screen);
677
 
 
678
 
  while (has_more (&p))
679
 
    {
680
 
      /* Skip comments (lines beginning with #).  */
681
 
      if (peek_char (&p) == '#')
682
 
        {
683
 
          advance_to_next_line (&p);
684
 
          continue;
685
 
        }
686
 
 
687
 
      /* Find the first non-whitespace character.  */
688
 
      skip_whitespace (&p);
689
 
 
690
 
      /* Handle the content.  */
691
 
      if (peek_char (&p) == '+')
692
 
        {
693
 
          /* Skip the '+'.  */
694
 
          read_char (&p);
695
 
          read_object (&p, view->canvas);
696
 
        }
697
 
      else
698
 
        {
699
 
          read_property (&p);
700
 
        }
701
 
 
702
 
      if (grub_errno != GRUB_ERR_NONE)
703
 
        goto fail;
704
 
    }
705
 
 
706
 
  /* Set the new theme path.  */
707
 
  grub_free (view->theme_path);
708
 
  view->theme_path = grub_strdup (theme_path);
709
 
  goto cleanup;
710
 
 
711
 
fail:
712
 
  if (view->canvas)
713
 
    {
714
 
      view->canvas->component.ops->destroy (view->canvas);
715
 
      view->canvas = 0;
716
 
    }
717
 
 
718
 
cleanup:
719
 
  grub_free (p.buf);
720
 
  grub_file_close (file);
721
 
  grub_free (p.theme_dir);
722
 
  return grub_errno;
723
 
}