Magellan Linux

Annotation of /trunk/busybox/patches/busybox-1.17.4-fbsplash-tykef-1.0.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1394 - (hide annotations) (download)
Fri Jul 1 13:33:50 2011 UTC (12 years, 10 months ago) by niro
File size: 48862 byte(s)
-tykef fbsplash patch
1 niro 1394 diff -Naur busybox-1.17.4/include/usage.src.h busybox-1.17.4-tykef/include/usage.src.h
2     --- busybox-1.17.4/include/usage.src.h 2010-11-22 21:24:58.000000000 +0100
3     +++ busybox-1.17.4-tykef/include/usage.src.h 2011-01-28 17:03:57.000000000 +0100
4     @@ -1222,7 +1222,8 @@
5     "1\n"
6    
7     #define fbsplash_trivial_usage \
8     - "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]"
9     + "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD] " \
10     + IF_FEATURE_FBSPLASH_FONTLOAD( "[-m FONTMAPFILE]" )
11     #define fbsplash_full_usage "\n\n" \
12     "Options:" \
13     "\n -s Image" \
14     @@ -1231,8 +1232,13 @@
15     "\n -i Config file (var=value):" \
16     "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" \
17     "\n BAR_R,BAR_G,BAR_B" \
18     + "\n TEXT_LEFT,TEXT_TOP,TEXT_R,TEXT_G,TEXT_B,TEXT_SIZE" \
19     "\n -f Control pipe (else exit after drawing image)" \
20     "\n commands: 'NN' (% for progress bar) or 'exit'" \
21     + IF_FEATURE_FBSPLASH_FONTLOAD( \
22     + "\n -m Font map file" \
23     + "\n commands: 'NN' (% for progress bar), 'write:string to print' or 'exit'" \
24     + )
25    
26     #define fbset_trivial_usage \
27     "[OPTIONS] [MODE]"
28     diff -Naur busybox-1.17.4/miscutils/Config.src busybox-1.17.4-tykef/miscutils/Config.src
29     --- busybox-1.17.4/miscutils/Config.src 2010-11-22 21:24:58.000000000 +0100
30     +++ busybox-1.17.4-tykef/miscutils/Config.src 2011-01-28 17:05:21.000000000 +0100
31     @@ -258,7 +258,8 @@
32     default y
33     help
34     Shows splash image and progress bar on framebuffer device.
35     - Can be used during boot phase of an embedded device. ~2kb.
36     + Can be used during boot phase of an embedded device.
37     + Code size is 2..7kb depends on enabled features.
38     Usage:
39     - use kernel option 'vga=xxx' or otherwise enable fb device.
40     - put somewhere fbsplash.cfg file and an image in .ppm format.
41     @@ -274,6 +275,44 @@
42     "NN" (ASCII decimal number) - percentage to show on progress bar
43     "exit" - well you guessed it
44    
45     +config FEATURE_FBSPLASH_8BPP
46     + bool "support 8bit depth with color mapping"
47     + depends on FBSPLASH
48     + help
49     + support for low color framebuffer that's need color mapping ~350 b
50     +
51     +config FEATURE_FBSPLASH_SPRITES
52     + bool "Render icons and animations"
53     + default n
54     + depends on FBSPLASH
55     + help
56     + This option adds the ability to display icons on the
57     + image displayed by the fbsplash applet. ~1.5kb.
58     + - command for fifo:
59     + "load:x:y:filename" - load images from file
60     + each sprite is one square area when image is wider than higher
61     + before load new sprite set, old area is cleared.
62     + "sprite:n" - show one sprite - sprite 0 is background.
63     + "anime:n:m:t" - anime from sprite n up/down to sprite m
64     + time between sprites is in t * 100 msec.
65     +
66     +config FEATURE_FBSPLASH_TEXT
67     + bool "text rendering"
68     + default n
69     + depends on FBSPLASH
70     + help
71     + This option adds the ability to print text messages on the
72     + image displayed by the fbsplash applet. ~2kb.
73     + - command for fifo:
74     + "write:string to print" - print the string after the word "write:"
75     +
76     +config FEATURE_FBSPLASH_FONTLOAD
77     + bool "font loading"
78     + depends on FEATURE_FBSPLASH_TEXT
79     + help
80     + The font is loaded from a standard console font file.
81     + Supported are psf v1.x and psf v2.0 files including mapping ~1kb.
82     +
83     config FLASHCP
84     bool "flashcp"
85     default n # doesn't build on Ubuntu 8.04
86     diff -Naur busybox-1.17.4/miscutils/fbsplash.c busybox-1.17.4-tykef/miscutils/fbsplash.c
87     --- busybox-1.17.4/miscutils/fbsplash.c 2010-11-22 21:24:58.000000000 +0100
88     +++ busybox-1.17.4-tykef/miscutils/fbsplash.c 2011-01-28 17:42:34.000000000 +0100
89     @@ -1,6 +1,7 @@
90     /* vi: set sw=4 ts=4: */
91     /*
92     * Copyright (C) 2008 Michele Sanges <michele.sanges@gmail.com>
93     + * Copyright (C) 2009 Jiri Gabriel <george.gabriel@seznam.cz>
94     *
95     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
96     *
97     @@ -10,42 +11,189 @@
98     * - run applet: $ setsid fbsplash [params] &
99     * -c: hide cursor
100     * -d /dev/fbN: framebuffer device (if not /dev/fb0)
101     - * -s path_to_image_file (can be "-" for stdin)
102     + * -s path_to_image_file - ppm or ppm.gz or ppm.bz2
103     * -i path_to_cfg_file
104     * -f path_to_fifo (can be "-" for stdin)
105     + * -m font map file - standard psf file (v1 and v2) can be with unumap
106     * - if you want to run it only in presence of a kernel parameter
107     * (for example fbsplash=on), use:
108     * grep -q "fbsplash=on" </proc/cmdline && setsid fbsplash [params]
109     * - commands for fifo:
110     * "NN" (ASCII decimal number) - percentage to show on progress bar.
111     - * "exit" (or just close fifo) - well you guessed it.
112     + * if number is smaller than zero progress bar is filled from left.
113     + * "write:string to print" - print the string after the word "write:"
114     + * "exit" - well you guessed it.
115     + */
116     +
117     +/*
118     + * enhancements:
119     + * - framebuffer can be in depth 8,15,16,24,32 PSEUDOCOLR,TRUECOLOR
120     + * not only 16
121     + * - image file cannot be stdin
122     + * - bugfix: if virtual size is bigger than visual resolution
123     + * - progress bar can be dscending for shutdown (-1..-100)
124     + * - progress bar is from background picture + color in cfg - only colorize.
125     + * - bouncing bar - command "bounce" and at start.
126     + * - smaller image is shown centered on screen cfg positions recalc on demand.
127     + * - without text rendering and sprites grow size is only 800b.
128     + * text rendering:
129     + * - font is standard psf console font
130     + * - if font not specified or not compiled in fontload function
131     + * font is used from kernel using KDFONTOP / GIO_FONTX / GIO_FONT
132     + * - colorize text render by \033[30m .. \033[37m,\033[1;30 .. \033[1;37m
133     + * sprites:
134     + * - animated sprites load by fifo command "load:x:y:filename".
135     + * File is ppm format may be gzipped/bzipped or raw.
136     + * Frame/Icon is always square. Width of each Frame is image height.
137     + * Frame number 0 is always created for save background.
138     + * Transparent color is in ppm file is stored as #FF00FF - purple.
139     + * Show frame by pipe command "sprite:n" where n is frame number.
140     + * Run animated sequence by "anime:n:m:t" where
141     + * n is first frame m is last frame, t is time between displaying
142     + * frames in 0.1sec. n can be bigger than m for reverse order in anime.
143     */
144    
145     #include "libbb.h"
146     +#if BB_BIG_ENDIAN
147     +#warning "fbsplash work only on little endian architecures. Sorry"
148     +int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
149     +int fbsplash_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) {
150     + bb_error_msg_and_die("fbsplash not work on big endian architectures.");
151     + return 1;
152     +}
153     +
154     +#else
155     #include <linux/fb.h>
156    
157     +#if ENABLE_FEATURE_FBSPLASH_TEXT
158     +#include <linux/kd.h>
159     +
160     +/* if you have fonts with sequences can turn this to 1 i not find any font with this feature
161     + ~510 bytes of code */
162     +#define ENABLE_FEATURE_FBSPLASH_PSFSEQS 0
163     +
164     +/* if you not use text colors and need optimize size - disable text colors
165     + ~250 bytes of code */
166     +#define ENABLE_FEATURE_FBSPLASH_TEXT_COLORS 1
167     +
168     +#if !defined(GIO_UNIMAP)
169     +struct unipair {
170     + unsigned short unicode;
171     + unsigned short fontpos;
172     +} __atribute__ ((packed));
173     +
174     +struct unimapdesc {
175     + unsigned short entry_ct;
176     + struct unipair *entries;
177     +} __atribute__ ((packed));
178     +#endif
179     +
180     +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD
181     +
182     +enum { // uint16
183     + PSF1_MAGIC = 0x0436,
184     + PSF1_SEPARATOR = 0xFFFF,
185     + PSF1_STARTSEQ = 0xFFFE
186     +};
187     +
188     +enum { // uint32
189     + PSF2_MAGIC = 0x864ab572,
190     + PSF2_HAS_UNICODE_TABLE = 0x01, /* bits used in flags */
191     + PSF2_MAXVERSION = 0 /* max version recognized so far */
192     +};
193     +
194     +enum { // uint8
195     + PSF1_MODE512 = 0x01,
196     + PSF1_MODEHASTAB = 0x02,
197     + PSF1_MODEHASSEQ = 0x04,
198     + PSF1_MAXMODE = 0x05,
199     + PSF2_STARTSEQ = 0xFE,
200     + PSF2_SEPARATOR = 0xFF
201     +};
202     +
203     +struct psf1_header {
204     + uint16_t magic; /* Magic number */
205     + uint8_t mode; /* PSF font mode */
206     + uint8_t charsize; /* Character size */
207     +} __attribute__ ((packed));
208     +
209     +struct psf2_header {
210     + uint32_t magic;
211     + uint32_t version;
212     + uint32_t headersize; /* offset of bitmaps in file */
213     + uint32_t flags;
214     + uint32_t length; /* number of glyphs */
215     + uint32_t charsize; /* number of bytes for each character */
216     + uint32_t height, width; /* max dimensions of glyphs */
217     + /* charsize = height * ((width + 7) / 8) */
218     +} __attribute__ ((packed));
219     +
220     +#endif // FONTLOAD
221     +struct fbfont {
222     + uint8_t *mem1;
223     + uint8_t *glyphs;
224     + struct unimapdesc ud;
225     + int height;
226     + int width;
227     + int glyphcount;
228     + int charsize;
229     + int rowbytes;
230     +};
231     +
232     +#endif
233     +
234     /* If you want logging messages on /tmp/fbsplash.log... */
235     #define DEBUG 0
236    
237     -#define BYTES_PER_PIXEL 2
238     +typedef uint32_t RGB;
239     +
240     +struct sprite {
241     + int w,h,bw; // width height in pixels, width in bytes
242     + uint8_t pixbuf[0];
243     +};
244    
245     -typedef unsigned short DATA;
246     +struct ppmfile {
247     + int fd;
248     + int sizx,sizy;
249     + int bufhead,buftail;
250     + uint8_t buf[0]; // buf for entire pixels row
251     +};
252    
253     struct globals {
254     #if DEBUG
255     bool bdebug_messages; // enable/disable logging
256     FILE *logfile_fd; // log file
257     #endif
258     - unsigned char *addr; // pointer to framebuffer memory
259     - unsigned ns[7]; // n-parameters
260     + unsigned char *addr; // pointer to visible framebuffer memory
261     + unsigned char *mapaddr; // pointer to framebuffer memory
262     +#if ENABLE_FEATURE_FBSPLASH_TEXT
263     + #define FBCFGVALS 13
264     +#else
265     + #define FBCFGVALS 7
266     +#endif
267     + unsigned ns[FBCFGVALS]; // n-parameters
268     const char *image_filename;
269     struct fb_var_screeninfo scr_var;
270     struct fb_fix_screeninfo scr_fix;
271     + int bytes_per_pixel,x0,y0; // offset for centering
272     + struct sprite *spb1,*spb2;
273     +#if ENABLE_FEATURE_FBSPLASH_TEXT
274     + struct fbfont *font;
275     + struct sprite *spt;
276     + uint8_t *unknown_glyph;
277     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
278     + uint8_t combglyph[4*32]; /* max width=32 max height=32 */
279     +#endif
280     +#endif
281     };
282     +
283     #define G (*ptr_to_globals)
284     #define INIT_G() do { \
285     SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
286     } while (0)
287     +#if ENABLE_FEATURE_FBSPLASH_TEXT
288     + #define GF (*(ptr_to_globals->font))
289     +#endif
290    
291     #define nbar_width ns[0] // progress bar width
292     #define nbar_height ns[1] // progress bar height
293     @@ -54,6 +202,75 @@
294     #define nbar_colr ns[4] // progress bar color red component
295     #define nbar_colg ns[5] // progress bar color green component
296     #define nbar_colb ns[6] // progress bar color blue component
297     +#define text_posx ns[7] // text horizontal position
298     +#define text_posy ns[8] // text vertical position
299     +#define text_colr ns[9] // text color red component
300     +#define text_colg ns[10] // text color green component
301     +#define text_colb ns[11] // text color blue component
302     +#define text_size ns[12] // text size (1 to 4)
303     +
304     +/**
305     + * A function to compute pixel value
306     + */
307     +static RGB FAST_FUNC makecol(uint16_t r, uint16_t g, uint16_t b) {
308     + if (r > 255) r = 255;
309     + if (g > 255) g = 255;
310     + if (b > 255) b = 255;
311     +#if ENABLE_FEATURE_FBSPLASH_8BPP
312     + if (G.bytes_per_pixel == 1) {
313     + // mymap is 6*8*5 = 240 values on offset 16
314     + // (r/42.6666) + (g/32) + (b/51.2)
315     + return 16 + (((r << 8) + r) / 13107) * 40 +
316     + (((g << 8) + g) / 9362) * 5 +
317     + (((b << 8) + b) / 16383);
318     + }
319     +#endif
320     + return ((r >> (8 - G.scr_var.red.length )) << G.scr_var.red.offset) |
321     + ((g >> (8 - G.scr_var.green.length)) << G.scr_var.green.offset) |
322     + ((b >> (8 - G.scr_var.blue.length )) << G.scr_var.blue.offset);
323     +}
324     +
325     +/*
326     + * A function to put the pixel row
327     + */
328     +static void fb_putpixrow(int x, int y, int w, uint8_t *rgb) {
329     + uint8_t *a;
330     + int realw;
331     + if (x < 0 || y < 0 || x > G.scr_var.xres || y > G.scr_var.yres) return;
332     + a = G.addr + G.scr_fix.line_length * y + G.bytes_per_pixel * x;
333     + realw = ((x + w) < G.scr_var.xres ? w : G.scr_var.xres - x) * G.bytes_per_pixel;
334     + memcpy(a,rgb,realw);
335     + return;
336     +}
337     +
338     +/*
339     + * A function to put the sprite to position or fill sprite from videoram
340     + */
341     +static void fb_sprite(int x, int y, int x0, int width, struct sprite *s, int direction) {
342     + uint8_t *a,*p;
343     + int realw,iy;
344     +
345     + if (x < 0 || y < 0 || x > G.scr_var.xres || y > G.scr_var.yres ||
346     + x0 >= s->w || x0 < 0 || width > (s->w - x0)) {
347     + return;
348     + }
349     + realw = ((x + width) < G.scr_var.xres ? width : (G.scr_var.xres - x)) * G.bytes_per_pixel;
350     + a = G.addr + G.scr_fix.line_length * y + G.bytes_per_pixel * x;
351     + p = &(s->pixbuf[x0 * G.bytes_per_pixel]);
352     + for (iy = 0; iy < s->h; iy++) {
353     + if ((iy + y) > G.scr_var.yres) break;
354     + if (direction == 1) {
355     + memcpy(p,a,realw);
356     + } else {
357     + memcpy(a,p,realw);
358     + }
359     + a += G.scr_fix.line_length;
360     + p += s->bw;
361     + }
362     + return;
363     +}
364     +#define fb_putsprite(x,y,s) fb_sprite(x,y,0,s->w,s,0)
365     +#define fb_getsprite(x,y,s) fb_sprite(x,y,0,s->w,s,1)
366    
367     #if DEBUG
368     #define DEBUG_MESSAGE(strMessage, args...) \
369     @@ -78,158 +295,117 @@
370     xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var);
371     xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix);
372    
373     - if (G.scr_var.bits_per_pixel != 16)
374     - bb_error_msg_and_die("only 16 bpp is supported");
375     -
376     +#if ENABLE_FEATURE_FBSPLASH_8BPP
377     + if ((G.scr_var.bits_per_pixel < 8) ||
378     + (G.scr_fix.type != FB_TYPE_PACKED_PIXELS)) {
379     + bb_error_msg_and_die("only 8,15,16,24 and 32 bpp is supported");
380     + }
381     +#else
382     + if ((G.scr_var.bits_per_pixel < 15) ||
383     + (G.scr_fix.type != FB_TYPE_PACKED_PIXELS)) {
384     + bb_error_msg_and_die("only 15,16,24 and 32 bpp is supported");
385     + }
386     +#endif
387     + switch (G.scr_fix.visual) {
388     +#if ENABLE_FEATURE_FBSPLASH_8BPP
389     + case FB_VISUAL_PSEUDOCOLOR: do {
390     + uint8_t *cmem;
391     + struct fb_cmap *cmap;
392     + int r,g,b,i;
393     + cmem = xzalloc(sizeof(struct fb_cmap) + sizeof(uint16_t) * 3 * 256);
394     + cmap = (struct fb_cmap *)cmem;
395     + cmap->len = 256;
396     + cmap->red = (uint16_t *)&(cmem[sizeof(struct fb_cmap)]);
397     + cmap->green = &(cmap->red[256]);
398     + cmap->blue = &(cmap->green[256]);
399     + xioctl(fbfd, FBIOGETCMAP, cmem); // read original palette
400     + // fill cmap with my 6x8x5 pallette
401     + for (r = 0,i = 16; r < 6; r++) {
402     + for (g = 0; g < 8; g++) {
403     + for (b = 0; b < 5; b++, i++) {
404     + cmap->red[i] = r * 13107;
405     + cmap->green[i] = g * 9362;
406     + cmap->blue[i] = b * 16383;
407     + }
408     + }
409     + }
410     + xioctl(fbfd, FBIOPUTCMAP, cmem);
411     + free(cmem);
412     + } while(0);
413     +#endif
414     + case FB_VISUAL_TRUECOLOR:
415     + break;
416     + default:
417     + bb_error_msg_and_die("only TrueColor modes is supported");
418     + }
419     +
420     + G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) / 8;
421     // map the device in memory
422     - G.addr = mmap(NULL,
423     - G.scr_var.xres * G.scr_var.yres
424     - * BYTES_PER_PIXEL /*(G.scr_var.bits_per_pixel / 8)*/,
425     + G.mapaddr = mmap(NULL,
426     + G.scr_var.yres_virtual * G.scr_fix.line_length ,
427     PROT_WRITE, MAP_SHARED, fbfd, 0);
428     - if (G.addr == MAP_FAILED)
429     + if (G.mapaddr == MAP_FAILED)
430     bb_perror_msg_and_die("mmap");
431     + G.addr = G.mapaddr + G.scr_var.yoffset * G.scr_fix.line_length;
432     close(fbfd);
433     }
434    
435    
436     /**
437     - * Draw hollow rectangle on framebuffer
438     - */
439     -static void fb_drawrectangle(void)
440     -{
441     - int cnt;
442     - DATA thispix;
443     - DATA *ptr1, *ptr2;
444     - unsigned char nred = G.nbar_colr/2;
445     - unsigned char ngreen = G.nbar_colg/2;
446     - unsigned char nblue = G.nbar_colb/2;
447     -
448     - nred >>= 3; // 5-bit red
449     - ngreen >>= 2; // 6-bit green
450     - nblue >>= 3; // 5-bit blue
451     - thispix = nblue + (ngreen << 5) + (nred << (5+6));
452     -
453     - // horizontal lines
454     - ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL);
455     - ptr2 = (DATA*)(G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL);
456     - cnt = G.nbar_width - 1;
457     - do {
458     - *ptr1++ = thispix;
459     - *ptr2++ = thispix;
460     - } while (--cnt >= 0);
461     -
462     - // vertical lines
463     - ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL);
464     - ptr2 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * BYTES_PER_PIXEL);
465     - cnt = G.nbar_height - 1;
466     - do {
467     - *ptr1 = thispix; ptr1 += G.scr_var.xres;
468     - *ptr2 = thispix; ptr2 += G.scr_var.xres;
469     - } while (--cnt >= 0);
470     -}
471     -
472     -
473     -/**
474     - * Draw filled rectangle on framebuffer
475     - * \param nx1pos,ny1pos upper left position
476     - * \param nx2pos,ny2pos down right position
477     - * \param nred,ngreen,nblue rgb color
478     - */
479     -static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos,
480     - unsigned char nred, unsigned char ngreen, unsigned char nblue)
481     -{
482     - int cnt1, cnt2, nypos;
483     - DATA thispix;
484     - DATA *ptr;
485     -
486     - nred >>= 3; // 5-bit red
487     - ngreen >>= 2; // 6-bit green
488     - nblue >>= 3; // 5-bit blue
489     - thispix = nblue + (ngreen << 5) + (nred << (5+6));
490     -
491     - cnt1 = ny2pos - ny1pos;
492     - nypos = ny1pos;
493     - do {
494     - ptr = (DATA*)(G.addr + (nypos * G.scr_var.xres + nx1pos) * BYTES_PER_PIXEL);
495     - cnt2 = nx2pos - nx1pos;
496     - do {
497     - *ptr++ = thispix;
498     - } while (--cnt2 >= 0);
499     -
500     - nypos++;
501     - } while (--cnt1 >= 0);
502     -}
503     -
504     -
505     -/**
506     * Draw a progress bar on framebuffer
507     - * \param percent percentage of loading
508     + * \param frompct percentage on which bar starting
509     + * \param topct percentage where bar end
510     */
511     -static void fb_drawprogressbar(unsigned percent)
512     +static void fb_drawnbar(int frompct, int topct)
513     {
514     - int i, left_x, top_y, width, height;
515     + int w0,w1,w2;
516    
517     - // outer box
518     - left_x = G.nbar_posx;
519     - top_y = G.nbar_posy;
520     - width = G.nbar_width - 1;
521     - height = G.nbar_height - 1;
522     - if ((height | width) < 0)
523     + if (G.spb1 == NULL || G.spb2 == NULL)
524     return;
525     - // NB: "width" of 1 actually makes rect with width of 2!
526     - fb_drawrectangle();
527     -
528     - // inner "empty" rectangle
529     - left_x++;
530     - top_y++;
531     - width -= 2;
532     - height -= 2;
533     - if ((height | width) < 0)
534     + if (frompct < 0 || frompct > 100 ||
535     + topct < 0 || topct > 100 ||
536     + frompct > topct) {
537     return;
538     - fb_drawfullrectangle(
539     - left_x, top_y,
540     - left_x + width, top_y + height,
541     - G.nbar_colr, G.nbar_colg, G.nbar_colb);
542     -
543     - if (percent > 0) {
544     - // actual progress bar
545     - width = width * percent / 100;
546     - i = height;
547     - if (height == 0)
548     - height++; // divide by 0 is bad
549     - while (i >= 0) {
550     - // draw one-line thick "rectangle"
551     - // top line will have gray lvl 200, bottom one 100
552     - unsigned gray_level = 100 + i*100/height;
553     - fb_drawfullrectangle(
554     - left_x, top_y, left_x + width, top_y,
555     - gray_level, gray_level, gray_level);
556     - top_y++;
557     - i--;
558     - }
559     }
560     +
561     + w0 = G.spb1->w * frompct / 100;
562     + w0 = (w0 > G.spb1->w ? G.spb1->w : w0);
563     + w2 = G.spb1->w * (100 - topct) / 100;
564     + w2 = ((w0 + w2) > G.spb1->w ? G.spb1->w - w0 : w2);
565     + w1 = G.spb1->w - w0 - w2;
566     + if (w0 > 0)
567     + fb_sprite(G.nbar_posx, G.nbar_posy, 0, w0, G.spb1, 0); // left "empty" area
568     + if (w1 > 0)
569     + fb_sprite(G.nbar_posx + w0, G.nbar_posy, w0, w1, G.spb2, 0); // filled area
570     + if (w2 > 0)
571     + fb_sprite(G.nbar_posx + w0 + w1, G.nbar_posy, w0 + w1, w2, G.spb1, 0); // right "empty" area
572     }
573    
574     +static struct sprite *fb_newsprite(int pw, int ph, int scrx, int scry) {
575     + struct sprite *s;
576     + s=xmalloc(sizeof(struct sprite) +
577     + ph * pw * G.bytes_per_pixel);
578     + s->w = pw;
579     + s->h = ph;
580     + s->bw = pw * G.bytes_per_pixel;
581     + if (scrx >= 0) fb_getsprite(scrx, scry, s); // read
582     + return s;
583     +}
584    
585     /**
586     - * Draw image from PPM file
587     + * Open PPM file - must be binary, color maxval 255
588     */
589     -static void fb_drawimage(void)
590     -{
591     - FILE *theme_file;
592     - char *read_ptr;
593     - unsigned char *pixline;
594     - unsigned i, j, width, height, line_size;
595     -
596     - if (LONE_DASH(G.image_filename)) {
597     - theme_file = stdin;
598     - } else {
599     - int fd = open_zipped(G.image_filename);
600     - if (fd < 0)
601     - bb_simple_perror_msg_and_die(G.image_filename);
602     - theme_file = xfdopen_for_read(fd);
603     - }
604     -
605     +static struct ppmfile *ppm_open(const char *filename) {
606     + int i,k,l,val;
607     + struct ppmfile *p;
608     + uint8_t *s;
609     + char *e;
610     +
611     + i = open_zipped(filename);
612     + if (i == -1) return NULL;
613     + p = (struct ppmfile *) xmalloc(sizeof(struct ppmfile) + 600);
614     + // initial buf 600 bytes header cannot be larger
615     + p->fd = i;
616     /* Parse ppm header:
617     * - Magic: two characters "P6".
618     * - Whitespace (blanks, TABs, CRs, LFs).
619     @@ -243,55 +419,744 @@
620     * - A raster of Width * Height pixels in triplets of rgb
621     * in pure binary by 1 or 2 bytes. (we support only 1 byte)
622     */
623     -#define concat_buf bb_common_bufsiz1
624     - read_ptr = concat_buf;
625     - while (1) {
626     - int w, h, max_color_val;
627     - int rem = concat_buf + sizeof(concat_buf) - read_ptr;
628     - if (rem < 2
629     - || fgets(read_ptr, rem, theme_file) == NULL
630     - ) {
631     - bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
632     - }
633     - read_ptr = strchrnul(read_ptr, '#');
634     - *read_ptr = '\0'; /* ignore #comments */
635     - if (sscanf(concat_buf, "P6 %u %u %u", &w, &h, &max_color_val) == 3
636     - && max_color_val <= 255
637     - ) {
638     - width = w; /* w is on stack, width may be in register */
639     - height = h;
640     - break;
641     + l=read(p->fd,&(p->buf[0]),600);
642     + if ((l < 0) || (p->buf[0] != 'P') || (p->buf[1] != '6')) {
643     + goto ppmopen_end;
644     + }
645     + for (s = &(p->buf[2]), i = 0, k = 0; s < &(p->buf[l]) && (k < 3); ) {
646     + switch (i) {
647     + case 0:
648     + if (*s <= ' ') {
649     + s++; // skip whitespaces
650     + } else {
651     + i++; // next state
652     + }
653     + break;
654     + case 1: // num or rmks
655     + if (*s == '#') {
656     + i = 2;
657     + } else {
658     + val=bb_strtoi((char *)s,&e,10);
659     + if (s == (uint8_t *)e) goto ppmopen_end; // no number - error
660     + s=(uint8_t *)e;
661     + i=0; // skip whitespaces
662     + switch (++k) {
663     + case 1: p->sizx = val; break;
664     + case 2: p->sizy = val; break;
665     + case 3:
666     + if (val > 255)
667     + goto ppmopen_end; // only 1 byte per color
668     + s++;
669     + p->bufhead = s - &(p->buf[0]);
670     + p->buftail = l;
671     + break;
672     + }
673     + }
674     + break;
675     + case 2: // skip to eol
676     + if (*s == 10) i=0;
677     + s++;
678     + break;
679     }
680     }
681     + if (p->sizx < 1 || p->sizy < 1) goto ppmopen_end;
682     + if (p->sizx > 200) {
683     + // buf is only 600 bytes = 200 pix prealocated - need more.
684     + p = xrealloc(p,sizeof(struct ppmfile) + 3 * p->sizx);
685     + }
686     + return p;
687     +
688     +ppmopen_end:
689     + close(p->fd);
690     + free(p);
691     + return NULL;
692     +}
693    
694     - line_size = width*3;
695     - pixline = xmalloc(line_size);
696     +/**
697     + * Read pixelline from ppm to internal buffer and return pointer
698     + */
699     +static uint8_t *ppm_readline(struct ppmfile *p) {
700     + int i;
701     + if (p==NULL) return NULL;
702     + if (p->bufhead < p->buftail) {
703     + // pack buffer
704     + for (i = 0; p->bufhead < p->buftail; i++) {
705     + p->buf[i]=p->buf[p->bufhead++];
706     + }
707     + p->buftail = i;
708     + } else {
709     + p->buftail = 0;
710     + }
711     + while (p->buftail < (p->sizx * 3)) {
712     + i=read(p->fd, &(p->buf[p->buftail]), (p->sizx * 3) - p->buftail);
713     + if (i < 0) return NULL;
714     + p->buftail += i;
715     + }
716     + p->bufhead = p->sizx * 3;
717     + return &(p->buf[0]);
718     +}
719     +
720     +/**
721     + * Close ppmfile
722     + */
723     +
724     +static void ppm_close(struct ppmfile *p) {
725     + if (p == NULL) return;
726     + close(p->fd);
727     + free(p);
728     +}
729     +
730     +/**
731     + * Draws a PPM image.
732     + */
733     +static void fb_drawimage(void)
734     +{
735     + struct ppmfile *ppm;
736     + unsigned char *pixel;
737     + unsigned char *rgbline,*rgbpix,*sprpix;
738     + RGB thispix;
739     + unsigned i, j, width, height;
740     +
741     + ppm = ppm_open(G.image_filename);
742     + if (ppm == NULL)
743     + bb_error_msg_and_die("PPM file %s cannot be opened",G.image_filename);
744     + width = ppm->sizx;
745     + height = ppm->sizy;
746     + if (width > G.scr_var.xres || height > G.scr_var.yres)
747     + bb_error_msg_and_die("PPM %dx%d does not match screen %dx%d",
748     + width, height, G.scr_var.xres, G.scr_var.yres);
749     + if (width > G.scr_var.xres)
750     + width = G.scr_var.xres;
751     + if (height > G.scr_var.yres)
752     + height = G.scr_var.yres;
753     +
754     + G.x0 = (width == G.scr_var.xres ? 0 : (G.scr_var.xres - width) / 2);
755     + G.y0 = (height == G.scr_var.yres ? 0 : (G.scr_var.yres - height) / 2);
756     + rgbline = xmalloc((width * G.bytes_per_pixel) + sizeof(RGB));
757    
758     - if (width > G.scr_var.xres)
759     - width = G.scr_var.xres;
760     - if (height > G.scr_var.yres)
761     - height = G.scr_var.yres;
762     for (j = 0; j < height; j++) {
763     - unsigned char *pixel;
764     - DATA *src;
765     + pixel = ppm_readline(ppm);
766     + rgbpix = rgbline;
767     + if (pixel == NULL)
768     + bb_error_msg_and_die("bad PPM file '%s' line %d", G.image_filename,j);
769     + if (G.spb2 != NULL && j >= G.nbar_posy && j < (G.nbar_posy + G.spb2->h)) {
770     + sprpix = &(G.spb2->pixbuf[(j - G.nbar_posy) * G.spb2->bw]);
771     + } else {
772     + sprpix = NULL;
773     + }
774    
775     - if (fread(pixline, 1, line_size, theme_file) != line_size)
776     - bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
777     - pixel = pixline;
778     - src = (DATA *)(G.addr + j * G.scr_fix.line_length);
779     for (i = 0; i < width; i++) {
780     - unsigned thispix;
781     - thispix = (((unsigned)pixel[0] << 8) & 0xf800)
782     - | (((unsigned)pixel[1] << 3) & 0x07e0)
783     - | (((unsigned)pixel[2] >> 3));
784     - *src++ = thispix;
785     + thispix = makecol(pixel[0],pixel[1],pixel[2]);
786     + *((RGB*)rgbpix) = thispix;
787     + if ((sprpix != NULL) && (i >= G.nbar_posx)) {
788     + if (G.nbar_colr >= 256) { // Multiple not add
789     + thispix = makecol((G.nbar_colr & 255) * pixel[0], (G.nbar_colg & 255) * pixel[1], (G.nbar_colb & 255) * pixel[2]);
790     + } else {
791     + thispix = makecol(G.nbar_colr + pixel[0], G.nbar_colg + pixel[1], G.nbar_colb + pixel[2]);
792     + }
793     + memcpy(sprpix,&thispix,G.bytes_per_pixel);
794     + if (i >= (G.nbar_posx + G.spb2->w - 1)) {
795     + sprpix = NULL;
796     + } else {
797     + sprpix += G.bytes_per_pixel;
798     + }
799     + }
800     pixel += 3;
801     + rgbpix += G.bytes_per_pixel;
802     }
803     + fb_putpixrow(G.x0,j + G.y0,width,rgbline);
804     }
805     - free(pixline);
806     - fclose(theme_file);
807     + free(rgbline);
808     + ppm_close(ppm);
809     + // recalc cfg if centered image
810     + G.nbar_posx += G.x0;
811     + G.nbar_posy += G.y0;
812     +#if ENABLE_FEATURE_FBSPLASH_TEXT
813     + G.text_posx += G.x0;
814     + G.text_posy += G.y0;
815     +#endif
816     }
817    
818     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
819     +/**
820     + * Read rectangle sprites from ppm file
821     + * \return pointer to array of sprites
822     + * \return number of sprites loaded
823     + */
824     +static struct sprite *fb_loadsprites(char *filename, int sx, int sy) {
825     + struct ppmfile *ppm;
826     + uint8_t *pixel, *rgbpix;
827     + struct sprite *s=NULL;
828     + int y,i;
829     + RGB thispix;
830     +
831     + if ((ppm = ppm_open(filename)) == NULL) goto readsprites_out;
832     + s = fb_newsprite(ppm->sizx + ppm->sizy, ppm->sizy, -1, -1);
833     + fb_sprite(sx + G.x0, sy + G.y0, 0, s->h, s, 1); // load square 0 - background
834     + rgbpix = &(s->pixbuf[0]);
835     + for (y = 0; y < ppm->sizy; y++) {
836     + // skip square 0
837     + rgbpix += s->h * G.bytes_per_pixel;
838     + // read from file
839     + pixel = ppm_readline(ppm);
840     + for (i = 0; (pixel != NULL) && (i < ppm->sizx); i++) {
841     + if (pixel[0]==0xFF && pixel[1]==0 && pixel[2]==0xFF) {
842     + // transparent color => get pixel from square 0
843     + memcpy(&thispix,
844     + &(s->pixbuf[y * s->bw + (i % s->h) * G.bytes_per_pixel]),
845     + G.bytes_per_pixel);
846     + } else {
847     + thispix = makecol(pixel[0],pixel[1],pixel[2]);
848     + }
849     + memcpy(rgbpix,&thispix,G.bytes_per_pixel);
850     + pixel += 3;
851     + rgbpix += G.bytes_per_pixel;
852     + }
853     + }
854     + ppm_close(ppm);
855     + return s;
856     +readsprites_out:
857     + if (s != NULL) free(s);
858     + return NULL;
859     +}
860     +
861     +#define fb_putanim(x,y,n,s) fb_sprite(x + G.x0,y + G.y0,s->h * n,s->h,s,0)
862     +#endif
863     +
864     +#if ENABLE_FEATURE_FBSPLASH_TEXT
865     +
866     +/*
867     + * A function to put the pixel
868     + */
869     +static void fb_putpixel(int x, int y, RGB rgb) {
870     + uint8_t *a;
871     + if (x < 0 || y < 0 || x > G.scr_var.xres || y > G.scr_var.yres) return;
872     + a=G.addr + G.scr_fix.line_length * y + G.bytes_per_pixel * x;
873     + memcpy(a,&rgb,G.bytes_per_pixel);
874     +/*
875     + switch (G.scr_var.bits_per_pixel) {
876     + case 8:
877     + *a = rgb & 0xFF;
878     + break;
879     + case 15:
880     + case 16:
881     + *((uint16_t *)a) = rgb & 0xFFFF;
882     + break;
883     + case 24:
884     + a[0] = rgb & 0xFF;
885     + a[1] = (rgb >> 8) & 0xFF;
886     + a[2] = (rgb >> 16) & 0xFF;
887     + break;
888     + case 32:
889     + *((uint32_t *)a) = rgb;
890     + break;
891     + }
892     +*/
893     + return;
894     +}
895     +
896     +/**
897     + * UTF-8 - get one charcter and advance to next
898     + * ??? this function may be in libbb ???
899     + * \return UCS4 value
900     + */
901     +static uint32_t ucs4value(uint8_t **s) {
902     + uint8_t *c;
903     + uint32_t ucs,w;
904     + int count;
905     +
906     + if (s==NULL || *s==NULL || **s==0) return 0;
907     + c = *s;
908     + ucs = *c++;
909     + if (ucs >= 0xC0) { /* 0x80..0xBF is error in utf8 but i use as-is */
910     + for (w = ucs & 0x7F, count = 0;(w & 0x40) == 0x40; count++) {
911     + w <<= 1;
912     + }
913     + ucs=ucs & (0x7E >> count);
914     + for(; count > 0; count--) {
915     + if ((*c & 0xC0) != 0x80) { /* error in utf8 */
916     + ucs=0;
917     + break;
918     + }
919     + ucs = (ucs << 6) + (*c++ & 0x3F);
920     + }
921     + }
922     + *s=c;
923     + return ucs;
924     +}
925     +
926     +/**
927     + * Find in GF.ud.entries desired UTF-8 char and advance to next char
928     + * can combine glyphs in own memory
929     + * \param s pointer to utf8 char pointer
930     + * \return pinter to glyph
931     + */
932     +static uint8_t *getglyph(uint8_t **s) {
933     + uint32_t ucs;
934     + uint8_t *c,*g;
935     + int utflen,i;
936     +
937     + if (s == NULL || *s == NULL || **s == 0)
938     + return G.unknown_glyph; /* end of string - no advance */
939     + c = *s;
940     + ucs = ucs4value(&c);
941     + utflen = c - *s;
942     + g = G.unknown_glyph;
943     + if (GF.ud.entries == NULL) {
944     + if (ucs < GF.glyphcount) {
945     + g = GF.glyphs + GF.charsize * ucs;
946     + }
947     + } else if (ucs <= 0xFFFF) { // only ucs2
948     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
949     + int j,compose;
950     + memset(G.combglyph,0,sizeof(G.combglyph));
951     + for (i = 0, compose=0; i < GF.ud.entry_ct; i++) {
952     + if (GF.ud.entries[i].unicode == ucs) {
953     + g=GF.glyphs +
954     + GF.ud.entries[i].fontpos * GF.charsize;
955     + for (j = 0; j < GF.charsize; j++) {
956     + G.combglyph[j] |= g[j];
957     + }
958     + compose++;
959     + }
960     + }
961     + if (compose > 1) { // found more than one
962     + g = &(G.combglyph[0]);
963     + }
964     +#else
965     + // no sequences - first found win
966     + for (i = 0; i < GF.ud.entry_ct ; i++) {
967     + if (GF.ud.entries[i].unicode == ucs) {
968     + g = GF.glyphs + GF.ud.entries[i].fontpos * GF.charsize;
969     + break;
970     + }
971     + }
972     +#endif
973     + }
974     + *s=c;
975     + return g;
976     +}
977     +
978     +/**
979     + * Draws a single character on framebuffer.
980     + * \param nXPos horizontal position from which draw the character.
981     + * \param nYPos vertical position from which draw the character.
982     + * \param nCharSize character scale factor [1..4].
983     + * \param pointer to *nChar character to draw - auto advance by utf8.
984     + * \param RGB color
985     + */
986     +static void fb_drawchar(int nXPos, int nYPos, int nCharSize,
987     + uint8_t **nChar, RGB thispix)
988     +{
989     + int x,y,px;
990     + uint8_t *glyph;
991     +
992     + if (G.font==NULL || GF.height==0 || GF.glyphs==NULL) return;
993     + if (G.unknown_glyph == NULL) {
994     + uint8_t *unknown;
995     + const uint8_t unconst[]="?";
996     + unknown=(uint8_t *)unconst;
997     + G.unknown_glyph = getglyph(&unknown);
998     + }
999     +
1000     + glyph=getglyph(nChar);
1001     + if (glyph==NULL) return;
1002     + glyph-=GF.rowbytes;
1003     + for (y = 0; y < (GF.height * nCharSize); y++) {
1004     + if ((y % nCharSize) == 0) glyph+=GF.rowbytes;
1005     + for (x = 0,px = -1; x < (GF.width * nCharSize); x++) {
1006     + if ((x % nCharSize) == 0) px++;
1007     + if ((glyph[px / 8] & (0x80 >> (px % 8))) != 0) {
1008     + fb_putpixel(nXPos + x, nYPos + y,thispix);
1009     + }
1010     + }
1011     + }
1012     +}
1013     +
1014     +
1015     +/**
1016     + * Draws a string on framebuffer.
1017     + * \param *strString pointer to the string.
1018     + */
1019     +static void fb_drawstring(char *strString)
1020     +{
1021     + RGB thispix;
1022     + int nCharSize;
1023     + int x;
1024     + uint8_t *c;
1025     +
1026     + // size check
1027     + nCharSize = G.text_size;
1028     + if (nCharSize < 1)
1029     + nCharSize = 1;
1030     + else if (nCharSize > 4)
1031     + nCharSize = 4;
1032     +
1033     + if (G.font==NULL || GF.height==0 || GF.glyphs==NULL) return;
1034     +
1035     + // redraws the portion of image interested to the old write operation
1036     + fb_putsprite(G.text_posx, G.text_posy, G.spt);
1037     +
1038     + // new write operation
1039     + thispix=makecol(G.text_colr,G.text_colg,G.text_colb);
1040     + for (x = G.text_posx, c = (uint8_t *)strString; *c != 0;) {
1041     +#if ENABLE_FEATURE_FBSPLASH_TEXT_COLORS
1042     + if (*c==0x1b && c[1]=='[') {
1043     + long newcol=0,first;
1044     + char *e;
1045     + e=(char *)&(c[1]);
1046     + do {
1047     + first=newcol;
1048     + ++e;
1049     + newcol = strtol(e,&e,10);
1050     + } while (*e == ';');
1051     + if (*e == 'm' && ((newcol == 0) || (newcol >= 30 && newcol <= 37))) {
1052     + if (newcol >= 30 && newcol <= 37) {
1053     + if (newcol == 0 && first == 1) {
1054     + thispix=makecol(0x33,0x33,0x33);
1055     + } else {
1056     + newcol -= 30;
1057     + first = (first == 1 ? 0xFF : 0xCC);
1058     + thispix=makecol((newcol & 1) ? first : 0,
1059     + (newcol & 2) ? first : 0,
1060     + (newcol & 4) ? first : 0);
1061     + }
1062     + } else {
1063     + thispix=makecol(G.text_colr,G.text_colg,G.text_colb);
1064     + }
1065     + c=(uint8_t *)(++e);
1066     + continue;
1067     + }
1068     + }
1069     +#endif
1070     + fb_drawchar(x, G.text_posy, nCharSize, &c, thispix);
1071     + x += GF.width * nCharSize;
1072     + if (x >= G.scr_var.xres) break; // too long string
1073     + }
1074     +}
1075     +
1076     +/**
1077     + * Free readed font structure with all allocated memory
1078     + */
1079     +static void fb_freefont(void) {
1080     + if (G.font != NULL) {
1081     + if (GF.mem1 != NULL) free(GF.mem1);
1082     + if (GF.ud.entries != NULL) free(GF.ud.entries);
1083     + free(G.font);
1084     + G.font=NULL;
1085     + }
1086     +}
1087     +
1088     +/**
1089     + * Read font and mapping from console using ioctl GIO_FONT and GIO_UNIMAP
1090     + */
1091     +static void fb_readvgafont(void) {
1092     + int fd,i;
1093     +#if (defined(KDFONTOP) && defined(KD_FONT_OP_GET)) || defined(GIO_FONTX)
1094     +#if defined(KDFONTOP) && defined(KD_FONT_OP_GET)
1095     + struct console_font_op fo;
1096     + fd = open(CURRENT_TTY,O_NONBLOCK);
1097     +// if (fd == -1) fd = open("/dev/tty0",O_NOCTTY);
1098     +// if (fd == -1) fd = open("/dev/tty1",O_NOCTTY);
1099     + if (fd == -1) return;
1100     +
1101     + fo.data = NULL;
1102     + fo.charcount = 0;
1103     + fo.height = 32; fo.width = 32; // max usable font size
1104     + fo.flags = 0;
1105     + fo.op = KD_FONT_OP_GET;
1106     + if (ioctl(fd, KDFONTOP, &fo) == 0) {
1107     + i = (fo.width + 7) / 8;
1108     + fo.data = xmalloc(fo.charcount * 32 * i);
1109     + if (ioctl(fd, KDFONTOP, &fo) == -1) {
1110     + free(fo.data);
1111     + goto fb_vgafontout;
1112     + }
1113     + }
1114     + if (G.font != NULL) fb_freefont();
1115     + G.font = (struct fbfont *) xzalloc(sizeof(struct fbfont));
1116     + GF.height = fo.height;
1117     + GF.glyphcount = fo.charcount;
1118     + GF.width = fo.width;
1119     + GF.rowbytes = (fo.width + 7) / 8;
1120     + GF.charsize = GF.height * GF.rowbytes;
1121     + GF.mem1 = (uint8_t *) xmalloc(GF.height * GF.glyphcount * GF.rowbytes);
1122     + GF.glyphs = GF.mem1;
1123     + for (i = 0; i < GF.glyphcount; i++) {
1124     + memcpy(&(GF.glyphs[i * GF.height * GF.rowbytes]),
1125     + &(fo.data[i * 32 * GF.rowbytes]),
1126     + GF.height * GF.rowbytes);
1127     + }
1128     + if (fo.data) free(fo.data);
1129     +#else // KDFONTOP / GIO_FONTX
1130     + struct consolefontdesc cfd;
1131     + int j;
1132     + fd = open(CURRENT_TTY,O_NONBLOCK);
1133     +// if (fd == -1) fd = open("/dev/tty0",O_NOCTTY);
1134     +// if (fd == -1) fd = open("/dev/tty1",O_NOCTTY);
1135     + if (fd == -1) return;
1136     +
1137     + cfd.chardata = NULL;
1138     + cfd.charcount = 0;
1139     + cfd.charheight = 0;
1140     + if (ioctl(fd, GIO_FONTX, &cfd) == 0) {
1141     + cfd.chardata = xmalloc(cfd.charcount * 32);
1142     + if (ioctl(fd, GIO_FONTX, &cfd) == -1) {
1143     + free(cfd.chardata);
1144     + goto fb_vgafontout;
1145     + }
1146     + } else {
1147     + cfd.charcount=256;
1148     + cfd.chardata = xmalloc(256 * 32);
1149     + if (ioctl(fd, GIO_FONT, cfd.chardata) != 0) {
1150     + free(cfd.chardata);
1151     + goto fb_vgafontout;
1152     + }
1153     + // compute real height
1154     + cfd.charheight=0;
1155     + for (j = 31; (j > 0) && (cfd.charheight == 0); j--) {
1156     + for (i = 0; (i < 256) && (cfd.charheight == 0); i++) {
1157     + if (cfd.chardata[i*32+j] != 0)
1158     + cfd.charheight=j;
1159     + }
1160     + }
1161     + }
1162     + if (cfd.charheight != 0) {
1163     + if (G.font != NULL) fb_freefont();
1164     + G.font = (struct fbfont *) xzalloc(sizeof(struct fbfont));
1165     + GF.charsize = cfd.charheight;
1166     + GF.height = GF.charsize;
1167     + GF.glyphcount = cfd.charcount;
1168     + GF.width = 8;
1169     + GF.rowbytes = 1;
1170     + GF.mem1 = (uint8_t *) xmalloc(GF.height * GF.glyphcount);
1171     + GF.glyphs = GF.mem1;
1172     + // pack font
1173     + for (i = 0; i < GF.glyphcount; i++) {
1174     + memcpy(&(GF.glyphs[i * GF.height]),
1175     + &(cfd.chardata[i * 32]),
1176     + GF.height);
1177     + }
1178     + }
1179     + free(cfd.chardata);
1180     +#endif // FONTOP / FONTX
1181     +#if defined(GIO_UNIMAP)
1182     + GF.ud.entry_ct = 0;
1183     + ioctl(fd, GIO_UNIMAP, &(GF.ud));
1184     + if (errno != ENOMEM) {
1185     + goto fb_vgafontout;
1186     + }
1187     + if (GF.ud.entry_ct > 0) {
1188     + GF.ud.entries = xmalloc(GF.ud.entry_ct * sizeof(struct unipair));
1189     + if (ioctl(fd, GIO_UNIMAP, &(GF.ud)) == -1) {
1190     + // error no unimap
1191     + free(GF.ud.entries);
1192     + GF.ud.entry_ct = 0;
1193     + }
1194     + }
1195     +#endif // GIO_UNIMAP
1196     +fb_vgafontout:
1197     + close(fd);
1198     +#endif // GIO_FONTX or KDFONTOP available
1199     + return;
1200     +}
1201     +
1202     +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD
1203     +
1204     +static uint16_t nextuni(int ver, uint8_t *map, int *pos) {
1205     + uint16_t rv;
1206     + int i;
1207     + i=*pos;
1208     + if (ver==1) {
1209     + rv = map[i + 1];
1210     + rv = (rv << 8) + map[i];
1211     + i += 2;
1212     + } else { // ver 2
1213     + if (map[i] == 0xFF) rv = 0xFFFF;
1214     + else if (map[i] == 0xFE) rv = 0xFFFE;
1215     + else if (map[i] < 0xC0) rv = map[i];
1216     + else if (map[i] < 0xE0) {
1217     + rv = map[i] & 0x1F;
1218     + if ((map[i + 1] & 0xC0) == 0x80)
1219     + rv = (rv << 6) + (map[++i] & 0x3F);
1220     + } else if (map[i] < 0xF0) {
1221     + rv = map[i] & 0x0F;
1222     + if ((map[i + 1] & 0xC0) == 0x80)
1223     + rv = (rv << 6) + (map[++i] & 0x3F);
1224     + if ((map[i + 1] & 0xC0) == 0x80)
1225     + rv = (rv << 6) + (map[++i] & 0x3F);
1226     + } else rv = map[i];
1227     + i++;
1228     + }
1229     + *pos=i;
1230     + return rv;
1231     +}
1232     +
1233     +/**
1234     + * Convert unimap from psf v1 and psf v2 to unimapdesc
1235     + */
1236     +static void convertmap(int ver, uint8_t *map, int mapsize, struct unimapdesc *ud) {
1237     + int i,j,k,glyph,glycodes;
1238     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1239     + int l, seqlen=0, *seq=NULL;
1240     +#endif
1241     + uint16_t e;
1242     + ud->entry_ct=0;
1243     + for (i = 0, glycodes=0; i < mapsize; ) {
1244     + e = nextuni(ver, map, &i);
1245     + if (e == PSF1_STARTSEQ) {
1246     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1247     + seqlen++;
1248     +#endif
1249     + e = nextuni(ver, map, &i);
1250     + while ((e != PSF1_SEPARATOR) && (i < mapsize)) {
1251     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1252     + ud->entry_ct += glycodes;
1253     +#endif
1254     + e = nextuni(ver, map, &i);
1255     + }
1256     + glycodes=0;
1257     + } else if (e == PSF1_SEPARATOR) {
1258     + ud->entry_ct += glycodes;
1259     + glycodes=0;
1260     + } else {
1261     + glycodes++;
1262     + }
1263     + }
1264     + ud->entries = (struct unipair *)
1265     + xmalloc(sizeof(struct unimapdesc) * ud->entry_ct);
1266     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1267     + if (seqlen > 0) {
1268     + seq = xzalloc(sizeof(int) * (seqlen + 1));
1269     + }
1270     +#endif
1271     + for (i = 0, glyph = 0, j = 0, k = 0; i < mapsize; ) {
1272     + e = nextuni(ver, map, &i);
1273     + if (e == PSF1_STARTSEQ) {
1274     + e = nextuni(ver, map, &i);
1275     + k++; // this is seqence - position saved
1276     + // remove sequence - this is not glyph
1277     + while (ud->entries[j-1].fontpos == glyph && j > 0) {
1278     + j--;
1279     + }
1280     + // skip chars in seq
1281     + while ((e != PSF1_SEPARATOR) && (i < mapsize)) {
1282     + e = nextuni(ver, map, &i);
1283     + }
1284     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1285     + if (k < seqlen) seq[k] = i;
1286     +#endif
1287     + } else if (e == PSF1_SEPARATOR) {
1288     + glyph++;
1289     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1290     + // next may be sequence
1291     + if (k < seqlen) seq[k] = i;
1292     +#endif
1293     + } else if (j < ud->entry_ct) {
1294     + ud->entries[j].unicode=e;
1295     + ud->entries[j++].fontpos=glyph;
1296     + }
1297     + }
1298     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1299     + i = 0;
1300     + while (i < seqlen) {
1301     + k = seq[i];
1302     + do {
1303     + e = nextuni(ver, map, &k);
1304     + } while (e != PSF1_STARTSEQ && e != PSF1_SEPARATOR && k < mapsize);
1305     + if (e == PSF1_STARTSEQ) {
1306     + e = nextuni(ver, map, &k);
1307     + while ((e != PSF1_SEPARATOR) && (k < mapsize)) {
1308     + // find glyph in table
1309     + glyph = 0;
1310     + while ((glyph < j) && (ud->entries[glyph].unicode != e)) {
1311     + glyph++;
1312     + }
1313     + // write glyph to table for all chars
1314     + if (glyph < j) { // found
1315     + l = seq[i]; // code pointer
1316     + e = nextuni(ver, map, &l);
1317     + while(e != PSF1_STARTSEQ && l < mapsize) {
1318     + ud->entries[j].unicode=e;
1319     + ud->entries[j++].fontpos=ud->entries[glyph].fontpos;
1320     + e = nextuni(ver, map, &l);
1321     + }
1322     + }
1323     + e = nextuni(ver, map, &k);
1324     + }
1325     + }
1326     + i++;
1327     + }
1328     + if (seqlen > 0) {
1329     + // remove unfound glyphs if any
1330     + ud->entry_ct = j;
1331     + free(seq);
1332     + }
1333     +#endif
1334     +}
1335     +
1336     +/**
1337     + * Read PSF v1 and PSF v2 fonts to own font structure
1338     + */
1339     +static void fb_readpsf(const char *filename) {
1340     + unsigned int len;
1341     + int maplen;
1342     + uint8_t *buf;
1343     + struct psf1_header *psf1;
1344     + struct psf2_header *psf2;
1345     +
1346     + if (G.font != NULL) fb_freefont();
1347     + len = 48*1024; // can't be larger
1348     + buf = xmalloc_open_zipped_read_close(filename, &len);
1349     + if (buf == NULL) {
1350     + bb_simple_perror_msg_and_die(filename);
1351     + }
1352     + if (len < 1024) {
1353     + goto badfmt;
1354     + }
1355     + G.font = (struct fbfont *) xzalloc(sizeof(struct fbfont));
1356     + GF.mem1 = buf;
1357     + psf1 = (struct psf1_header *)buf;
1358     + psf2 = (struct psf2_header *)buf;
1359     + if ((psf1->magic == PSF1_MAGIC) && (psf1->mode <= PSF1_MAXMODE)) {
1360     + GF.glyphs = &(buf[sizeof(struct psf1_header)]);
1361     + GF.charsize = psf1->charsize;
1362     + GF.height = GF.charsize;
1363     + GF.glyphcount = ((psf1->mode & PSF1_MODE512) ? 512 : 256);
1364     + GF.width = 8;
1365     + maplen = len - sizeof(struct psf1_header) -
1366     + (GF.charsize * GF.glyphcount);
1367     + if ((maplen > 0) && ((psf1->mode & PSF1_MODEHASTAB) != 0)) {
1368     + convertmap(1,&(buf[len - maplen]),maplen,&(GF.ud));
1369     + } else {
1370     + if (maplen < 0) goto badfmt;
1371     + }
1372     + } else if ((psf2->magic == PSF2_MAGIC) &&
1373     + (psf2->version <= PSF2_MAXVERSION)) {
1374     + GF.glyphs=&(buf[psf2->headersize]);
1375     + GF.height = psf2->height;
1376     + GF.width = psf2->width;
1377     + GF.glyphcount = psf2->length;
1378     + GF.charsize = psf2->charsize;
1379     + maplen = len - psf2->headersize -
1380     + (GF.charsize * GF.glyphcount);
1381     + if ((maplen > 0) && ((psf2->flags & PSF2_HAS_UNICODE_TABLE) != 0)) {
1382     + convertmap(2,&(buf[len - maplen]),maplen,&(GF.ud));
1383     + } else {
1384     + if (maplen < 0) goto badfmt;
1385     + }
1386     + } else {
1387     + goto badfmt;
1388     + }
1389     + GF.rowbytes = GF.charsize / GF.height;
1390     +
1391     + return;
1392     +badfmt:
1393     + if (G.font) fb_freefont();
1394     + bb_error_msg_and_die("Cannot read file %s - unrecognized format\n",filename);
1395     +}
1396     +#endif // FONTLOAD
1397     +#endif // TEXT
1398    
1399     /**
1400     * Parse configuration file
1401     @@ -303,6 +1168,9 @@
1402     "BAR_WIDTH\0" "BAR_HEIGHT\0"
1403     "BAR_LEFT\0" "BAR_TOP\0"
1404     "BAR_R\0" "BAR_G\0" "BAR_B\0"
1405     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1406     + "TEXT_LEFT\0" "TEXT_TOP\0" "TEXT_R\0" "TEXT_G\0" "TEXT_B\0" "TEXT_SIZE\0"
1407     +#endif
1408     #if DEBUG
1409     "DEBUG\0"
1410     #endif
1411     @@ -310,15 +1178,15 @@
1412     char *token[2];
1413     parser_t *parser = config_open2(cfg_filename, xfopen_stdin);
1414     while (config_read(parser, token, 2, 2, "#=",
1415     - (PARSE_NORMAL | PARSE_MIN_DIE) & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
1416     + (PARSE_NORMAL | PARSE_MIN_DIE) & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
1417     unsigned val = xatoi_u(token[1]);
1418     int i = index_in_strings(param_names, token[0]);
1419     if (i < 0)
1420     bb_error_msg_and_die("syntax error: %s", token[0]);
1421     - if (i >= 0 && i < 7)
1422     + if (i >= 0 && i < FBCFGVALS)
1423     G.ns[i] = val;
1424     #if DEBUG
1425     - if (i == 7) {
1426     + if (i == FBCFGVALS) {
1427     G.bdebug_messages = val;
1428     if (G.bdebug_messages)
1429     G.logfile_fd = xfopen_for_write("/tmp/fbsplash.log");
1430     @@ -332,11 +1200,24 @@
1431     int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1432     int fbsplash_main(int argc UNUSED_PARAM, char **argv)
1433     {
1434     +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD
1435     + const char *fontmap_filename = NULL;
1436     +#endif
1437     const char *fb_device, *cfg_filename, *fifo_filename;
1438     - FILE *fp = fp; // for compiler
1439     - char *num_buf;
1440     - unsigned num;
1441     + char num_buf[512];
1442     + int num;
1443     bool bCursorOff;
1444     + struct timeval tim;
1445     + fd_set rdfds;
1446     + FILE *fp=fp;
1447     + int bounce_x=0;
1448     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
1449     + int anim_x,anim_y, /* position of sprite or animation */
1450     + anim_n,anim_m, /* min sprite, max sprite for animation */
1451     + anim_p=0, /* actual sprite */
1452     + anim_t=0,anim_now=0; /* time between steps */
1453     + struct sprite *spa=NULL;
1454     +#endif
1455    
1456     INIT_G();
1457    
1458     @@ -344,9 +1225,19 @@
1459     fb_device = "/dev/fb0";
1460     cfg_filename = NULL;
1461     fifo_filename = NULL;
1462     +
1463     +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD
1464     + bCursorOff = 1 & getopt32(argv, "cs:d:i:f:m:",
1465     + &G.image_filename, &fb_device, &cfg_filename, &fifo_filename, &fontmap_filename);
1466     +
1467     + if (fontmap_filename) fb_readpsf(fontmap_filename);
1468     +#else
1469     bCursorOff = 1 & getopt32(argv, "cs:d:i:f:",
1470     &G.image_filename, &fb_device, &cfg_filename, &fifo_filename);
1471     -
1472     +#endif
1473     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1474     + if (G.font==NULL) fb_readvgafont();
1475     +#endif
1476     // parse configuration file
1477     if (cfg_filename)
1478     init(cfg_filename);
1479     @@ -362,8 +1253,20 @@
1480     full_write(STDOUT_FILENO, "\033[?25l", 6);
1481     }
1482    
1483     + if (fifo_filename != NULL) {
1484     + G.spb2 = fb_newsprite(G.nbar_width, G.nbar_height, -1, -1);
1485     + }
1486     +
1487     fb_drawimage();
1488    
1489     + G.spb1 = fb_newsprite(G.nbar_width, G.nbar_height, G.nbar_posx, G.nbar_posy);
1490     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1491     + if (G.font != NULL)
1492     + G.spt = fb_newsprite(G.scr_var.xres - G.text_posx,
1493     + GF.height * G.text_size,
1494     + G.text_posx, G.text_posy);
1495     +#endif
1496     +
1497     if (!fifo_filename)
1498     return EXIT_SUCCESS;
1499    
1500     @@ -380,31 +1283,137 @@
1501     // when last writer closes input end.
1502     // The simplest way is to open fifo for writing too
1503     // and become an additional writer :)
1504     - open(fifo_filename, O_WRONLY); // errors are ignored
1505     + open(fifo_filename, O_WRONLY | O_NDELAY); // errors are ignored
1506     }
1507    
1508     - fb_drawprogressbar(0);
1509     // Block on read, waiting for some input.
1510     // Use of <stdio.h> style I/O allows to correctly
1511     // handle a case when we have many buffered lines
1512     // already in the pipe
1513     - while ((num_buf = xmalloc_fgetline(fp)) != NULL) {
1514     - if (strncmp(num_buf, "exit", 4) == 0) {
1515     - DEBUG_MESSAGE("exit");
1516     - break;
1517     - }
1518     - num = atoi(num_buf);
1519     - if (isdigit(num_buf[0]) && (num <= 100)) {
1520     + // select and fgets work just in time only in nobuf mode
1521     + setvbuf(fp, NULL, _IONBF, 0);
1522     + tim.tv_sec = 0;
1523     + tim.tv_usec = 100000;
1524     + while (1) {
1525     + FD_ZERO(&rdfds);
1526     + FD_SET(fileno(fp),&rdfds);
1527     + if ((num=select(fileno(fp) + 1,&rdfds,NULL,NULL,&tim))==-1)
1528     + break; // select error
1529     + if (num != 0 && fgets(num_buf,sizeof(num_buf) - 1,fp) != NULL) {
1530     + num_buf[sizeof(num_buf) - 1]=0;
1531     + num=strlen(num_buf) - 1;
1532     + if (num >= 0 && num_buf[num]==10) num_buf[num]=0;
1533     + if (strncmp(num_buf, "exit", 4) == 0) {
1534     + DEBUG_MESSAGE("exit");
1535     + break;
1536     + } else if (strncmp(num_buf, "bounce", 6) == 0) {
1537     + bounce_x = 0;
1538     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1539     + } else if (strncmp(num_buf, "write:", 6) == 0) {
1540     + if (G.font!=NULL) fb_drawstring(num_buf + 6);
1541     + DEBUG_MESSAGE(num_buf);
1542     +#endif
1543     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
1544     + } else if (strncmp(num_buf, "load:", 5) == 0) {
1545     + if (spa) {
1546     + fb_putanim(anim_x,anim_y,0,spa); // hide old
1547     + free(spa);
1548     + spa=NULL;
1549     + }
1550     + if (sscanf(&(num_buf[5]),"%d:%d:",
1551     + &anim_x,&anim_y) == 2) {
1552     + // skip x:y
1553     + for (num=5;num_buf[num] != ':';) num++;
1554     + for (num++;num_buf[num] != ':';) num++;
1555     + spa=fb_loadsprites(&(num_buf[num + 1]),anim_x,anim_y);
1556     + anim_t = anim_now = 0; // stop animation
1557     + }
1558     + } else if (strncmp(num_buf, "sprite:", 7) == 0) {
1559     + if (spa != NULL) {
1560     + // "sprite:n"
1561     + anim_t = anim_now = 0; // stop animation
1562     + anim_p = atoi(&(num_buf[7]));
1563     + if (anim_p >= 0) {
1564     + fb_putanim(anim_x,anim_y,anim_p,spa);
1565     + }
1566     + }
1567     + } else if (strncmp(num_buf, "anime:", 6) == 0) {
1568     + if (spa != NULL) {
1569     + // "anime:n:m:t"
1570     + if ((sscanf(&(num_buf[6]),"%d:%d:%d",
1571     + &anim_n,&anim_m,&anim_t) == 3) &&
1572     + (anim_n >= 0) && (anim_m >= 0)) {
1573     + anim_p = anim_n; // first frame
1574     + fb_putanim(anim_x,anim_y,anim_p,spa);
1575     + anim_now = anim_t; // next sprite after time t
1576     + } else {
1577     + anim_now = anim_t = 0; // stop animation
1578     + }
1579     + }
1580     +#endif
1581     + } else {
1582     + num = atoi(num_buf);
1583     + if ((isdigit(num_buf[0]) || (num_buf[0]=='-')) &&
1584     + (num >= -100 && num <= 100)) {
1585     #if DEBUG
1586     - DEBUG_MESSAGE(itoa(num));
1587     + char strVal[10];
1588     + sprintf(strVal, "%d", num);
1589     + DEBUG_MESSAGE(strVal);
1590     +#endif
1591     + if (num < 0) {
1592     + fb_drawnbar(-1 * num,100);
1593     + } else {
1594     + fb_drawnbar(0,num);
1595     + }
1596     + bounce_x = -1; // stop bounce
1597     + }
1598     + }
1599     + } else {
1600     + if (fp == stdin && feof(fp)) break; // stdin closed END
1601     + }
1602     + if (tim.tv_usec == 0) { // timeout - anime
1603     + tim.tv_usec = 100000;
1604     + if (bounce_x >= 0) {
1605     + bounce_x += 5;
1606     + if (bounce_x > 160) bounce_x = 0;
1607     + if (bounce_x > 80)
1608     + fb_drawnbar(160 - bounce_x,180 - bounce_x);
1609     + else
1610     + fb_drawnbar(bounce_x, bounce_x + 20);
1611     + }
1612     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
1613     + if (spa != NULL && anim_t != 0) {
1614     + --anim_now;
1615     + if (anim_now <= 0) {
1616     + anim_now = anim_t; // wait
1617     + if (anim_n < anim_m) {
1618     + anim_p++;
1619     + if (anim_p > anim_m) anim_p = anim_n;
1620     + } else {
1621     + anim_p--;
1622     + if (anim_p < anim_m) anim_p = anim_n;
1623     + }
1624     + fb_putanim(anim_x,anim_y,anim_p,spa);
1625     + }
1626     + }
1627     #endif
1628     - fb_drawprogressbar(num);
1629     }
1630     - free(num_buf);
1631     }
1632     -
1633     + if (G.spb1 != NULL) free(G.spb1);
1634     + G.spb1 = NULL;
1635     + if (G.spb2 != NULL) free(G.spb2);
1636     + G.spb2 = NULL;
1637     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1638     + if (G.font != NULL) fb_freefont();
1639     + if (G.spt != NULL) free(G.spt);
1640     + G.spt = NULL;
1641     +#endif
1642     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
1643     + if (spa != NULL) free(spa);
1644     +#endif
1645     if (bCursorOff) // restore cursor
1646     full_write(STDOUT_FILENO, "\033[?25h", 6);
1647    
1648     return EXIT_SUCCESS;
1649     }
1650     +#endif
1651     diff -Naur busybox-1.17.4/miscutils/fbsplash.cfg busybox-1.17.4-tykef/miscutils/fbsplash.cfg
1652     --- busybox-1.17.4/miscutils/fbsplash.cfg 2010-11-22 21:24:13.000000000 +0100
1653     +++ busybox-1.17.4-tykef/miscutils/fbsplash.cfg 2011-01-28 17:43:00.000000000 +0100
1654     @@ -7,3 +7,13 @@
1655     BAR_R=80
1656     BAR_G=80
1657     BAR_B=130
1658     +# the below settings are active only if you enable the option FBSPLASH_TEXT_RENDERING
1659     +# text position
1660     +#TEXT_LEFT=100
1661     +#TEXT_TOP=350
1662     +## text color
1663     +#TEXT_R=80
1664     +#TEXT_G=80
1665     +#TEXT_B=130
1666     +## text size (1 to 4)
1667     +#TEXT_SIZE=2