Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1044 - (hide annotations) (download)
Sat May 8 10:56:35 2010 UTC (14 years, 1 month ago) by niro
File size: 55144 byte(s)
-adds some advanced features to fbslash

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