ClipPlus BOOTLOADER DONT FIT!
REMOVED FROM ALL NATIVE BOOTLOADERS: finish removing the text scrolling pare down printf to a minimal subset (%c %s %l %d %u and %x(%p)) remove diacritic and rtl language support GOAL 134000 START 135305 CURRENT 133700 SUCCESS! (ASSUMING IT WORKS -- UNESTED) Change-Id: Ic3f6ac1dc260578f581ee53458b3e5bb47d313ec
This commit is contained in:
parent
a8aa8403ad
commit
d78a37676e
7 changed files with 529 additions and 3 deletions
|
@ -1,4 +1,6 @@
|
|||
common.c
|
||||
format.c
|
||||
snprintf.c
|
||||
|
||||
#if defined(IPOD_NANO2G)
|
||||
ipodnano2g.c
|
||||
|
|
324
bootloader/format.c
Normal file
324
bootloader/format.c
Normal file
|
@ -0,0 +1,324 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 by Gary Czvitkovicz
|
||||
* Copyright (C) 2017 by William Wilgus
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "file.h"
|
||||
#include "format.h"
|
||||
|
||||
static const char hexdigit[] = "0123456789ABCDEF";
|
||||
|
||||
/* smaller compressed binary without inline but 18% slower */
|
||||
#define FMT_DECL static inline
|
||||
|
||||
FMT_DECL int fmt_width_precision(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
int value = 0;
|
||||
(void) str;
|
||||
(void) ap;
|
||||
|
||||
while (*ch >= '0' && *ch <= '9')
|
||||
{
|
||||
value = 10 * value + (*ch - '0');
|
||||
*ch = *(*fmt)++;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
FMT_DECL int fmt_integer_signed(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
int val, rem, sign;
|
||||
(void) ch;
|
||||
(void) fmt;
|
||||
|
||||
val = sign = va_arg(*ap, int);
|
||||
if (val < 0)
|
||||
val = -val;
|
||||
do {
|
||||
rem = val % 10;
|
||||
val /= 10;
|
||||
*--(*str) = rem + '0';
|
||||
|
||||
} while (val > 0);
|
||||
|
||||
if (sign < 0)
|
||||
*--(*str) = '-';
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_DECL int fmt_integer_unsigned(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
unsigned int uval, urem;
|
||||
(void) ch;
|
||||
(void) fmt;
|
||||
|
||||
uval = va_arg(*ap, unsigned int);
|
||||
do {
|
||||
urem = uval % 10;
|
||||
uval /= 10;
|
||||
*--(*str) = urem + '0';
|
||||
} while (uval > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_DECL int fmt_long(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
int pad = 0;
|
||||
long lval, lrem, lsign = 0;
|
||||
unsigned long ulval, ulrem;
|
||||
char ch_l = *ch;
|
||||
|
||||
*ch = *(*fmt)++;
|
||||
if (*ch == 'd') {
|
||||
lval = lsign = va_arg(*ap, long);
|
||||
|
||||
if (lval < 0)
|
||||
lval = -lval;
|
||||
do {
|
||||
lrem = lval % 10;
|
||||
lval /= 10;
|
||||
*--(*str) = lrem + '0';
|
||||
} while (lval > 0);
|
||||
|
||||
if (lsign < 0)
|
||||
*--(*str) = '-';
|
||||
}
|
||||
else if (*ch == 'u') {
|
||||
ulval = va_arg(*ap, unsigned long);
|
||||
do {
|
||||
ulrem = ulval % 10;
|
||||
ulval /= 10;
|
||||
*--(*str) = ulrem + '0';
|
||||
} while (ulval > 0);
|
||||
}
|
||||
else if (*ch == 'x' || *ch == 'X') {
|
||||
pad++;
|
||||
ulval = va_arg(*ap, long);
|
||||
do {
|
||||
*--(*str) = hexdigit[ulval & 0xf];
|
||||
ulval >>= 4;
|
||||
} while (ulval > 0);
|
||||
}
|
||||
else {
|
||||
*--(*str) = ch_l;
|
||||
*--(*str) = *ch;
|
||||
}
|
||||
return pad;
|
||||
}
|
||||
|
||||
FMT_DECL int fmt_character(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
(void) ch;
|
||||
(void) fmt;
|
||||
|
||||
*--(*str) = va_arg(*ap, int);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_DECL int fmt_string(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
(void) ch;
|
||||
(void) fmt;
|
||||
|
||||
*str = va_arg (*ap, char*);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_DECL int fmt_hex_unsigned(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
unsigned int uval;
|
||||
(void) ch;
|
||||
(void) fmt;
|
||||
|
||||
uval = va_arg(*ap, int);
|
||||
do {
|
||||
*--(*str) = hexdigit[uval & 0xf];
|
||||
uval >>= 4;
|
||||
} while (uval > 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FMT_DECL int fmt_pointer(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
int pad = fmt_hex_unsigned(ch, fmt, str, ap);
|
||||
/* for pointers prepend 0x and act like 'X' */
|
||||
*--(*str) = 'x';
|
||||
*--(*str) = '0';
|
||||
return pad;
|
||||
}
|
||||
|
||||
FMT_DECL int fmt_sizet(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
size_t uszval, uszrem;
|
||||
ssize_t szval, szrem, szsign;
|
||||
char ch_z = *ch;
|
||||
*ch = *(*fmt)++;
|
||||
|
||||
if (*ch == 'd') {
|
||||
szval = szsign = va_arg(*ap, ssize_t);
|
||||
if (szval < 0)
|
||||
szval = -szval;
|
||||
do {
|
||||
szrem = szval % 10;
|
||||
szval /= 10;
|
||||
*--(*str) = szrem + '0';
|
||||
} while (szval > 0);
|
||||
|
||||
if (szsign < 0)
|
||||
*--(*str) = '-';
|
||||
}
|
||||
else if (*ch == 'u') {
|
||||
uszval = va_arg(*ap, size_t);
|
||||
do {
|
||||
uszrem = uszval % 10;
|
||||
uszval /= 10;
|
||||
*--(*str) = uszrem + '0';
|
||||
} while (uszval > 0);
|
||||
}
|
||||
else {
|
||||
*--(*str) = ch_z;
|
||||
*--(*str) = *ch;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fmt_next_char(int *ch, const char **fmt, char **str, va_list *ap)
|
||||
{
|
||||
(void) fmt;
|
||||
(void) ap;
|
||||
|
||||
*--(*str) = *ch;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void format(
|
||||
/* call 'push()' for each output letter */
|
||||
int (*push)(void *userp, unsigned char data),
|
||||
void *userp,
|
||||
const char *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
bool ok = true;
|
||||
char *str;
|
||||
char tmpbuf[12], pad;
|
||||
int ch, width, precision, padded;
|
||||
|
||||
|
||||
ch = *fmt++;
|
||||
tmpbuf[sizeof tmpbuf - 1] = '\0';
|
||||
|
||||
do
|
||||
{
|
||||
if (ch == '%')
|
||||
{
|
||||
str = tmpbuf + sizeof tmpbuf - 1;
|
||||
ch = *fmt++;
|
||||
padded = (ch == '0' ? 1 : 0);
|
||||
width = fmt_width_precision(&ch, &fmt, &str, &ap);
|
||||
|
||||
precision = INT_MAX;
|
||||
if(ch == '.')
|
||||
{
|
||||
ch = *fmt++;
|
||||
precision = fmt_width_precision(&ch, &fmt, &str, &ap);
|
||||
}
|
||||
|
||||
if (ch == 'd')
|
||||
fmt_integer_signed(&ch, &fmt, &str, &ap);
|
||||
else if (ch == 'u')
|
||||
fmt_integer_unsigned(&ch, &fmt, &str, &ap);
|
||||
else if (ch == 'l')
|
||||
padded += fmt_long(&ch, &fmt, &str, &ap);
|
||||
else if (ch == 'c')
|
||||
fmt_character(&ch, &fmt, &str, &ap);
|
||||
else if (ch == 's')
|
||||
fmt_string(&ch, &fmt, &str, &ap);
|
||||
else if (ch == 'x' || ch == 'X')
|
||||
padded += fmt_hex_unsigned(&ch, &fmt, &str, &ap);
|
||||
else if (ch == 'p' || ch == 'P')
|
||||
padded += fmt_pointer(&ch, &fmt, &str, &ap);
|
||||
#if 0
|
||||
else if (ch == 'z')
|
||||
fmt_sizet(&ch, &fmt, &str, &ap);
|
||||
#endif
|
||||
else
|
||||
fmt_next_char(&ch, &fmt, &str, &ap);
|
||||
|
||||
width -= strlen (str);
|
||||
if (width > 0)
|
||||
{
|
||||
pad = (padded ? '0' : ' ');
|
||||
while (width-- > 0 && ok)
|
||||
ok=push(userp, pad);
|
||||
}
|
||||
while(*str != '\0' && ok && precision--)
|
||||
ok=push(userp, *str++);
|
||||
}
|
||||
else
|
||||
ok=push(userp, ch);
|
||||
|
||||
} while ((ch = *fmt++) != '\0' && ok);
|
||||
}
|
||||
|
||||
struct for_fprintf {
|
||||
int fd; /* where to store it */
|
||||
int bytes; /* amount stored */
|
||||
};
|
||||
|
||||
static int fprfunc(void *pr, unsigned char letter)
|
||||
{
|
||||
struct for_fprintf *fpr = (struct for_fprintf *)pr;
|
||||
int rc = write(fpr->fd, &letter, 1);
|
||||
|
||||
if(rc > 0) {
|
||||
fpr->bytes++; /* count them */
|
||||
return true; /* we are ok */
|
||||
}
|
||||
|
||||
return false; /* failure */
|
||||
}
|
||||
|
||||
|
||||
int fdprintf(int fd, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct for_fprintf fpr;
|
||||
|
||||
fpr.fd=fd;
|
||||
fpr.bytes=0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
format(fprfunc, &fpr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return fpr.bytes; /* return 0 on error */
|
||||
}
|
||||
|
||||
void vuprintf(int (*push)(void *userp, unsigned char data), void *userp, const char *fmt, va_list ap)
|
||||
{
|
||||
format(push, userp, fmt, ap);
|
||||
}
|
37
bootloader/format.h
Normal file
37
bootloader/format.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 by Felix Arends
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __FORMAT_H__
|
||||
#define __FORMAT_H__
|
||||
|
||||
void format(
|
||||
/* call 'push()' for each output letter */
|
||||
int (*push)(void *userp, unsigned char data),
|
||||
void *userp,
|
||||
const char *fmt,
|
||||
va_list ap);
|
||||
|
||||
/* callback function is called for every output character (byte) with userp and
|
||||
* should return 0 when ch is a char other than '\0' that should stop printing */
|
||||
void vuprintf(int (*push)(void *userp, unsigned char data),
|
||||
void *userp, const char *fmt, va_list ap);
|
||||
|
||||
#endif /* __FORMAT_H__ */
|
80
bootloader/snprintf.c
Normal file
80
bootloader/snprintf.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 by Gary Czvitkovicz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Minimal printf and snprintf formatting functions
|
||||
*
|
||||
* These support %c %s %l %d %u and %x(%p)
|
||||
* Field width and zero-padding flag only
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include "format.h"
|
||||
|
||||
struct for_snprintf {
|
||||
unsigned char *ptr; /* where to store it */
|
||||
size_t bytes; /* amount already stored */
|
||||
size_t max; /* max amount to store */
|
||||
};
|
||||
|
||||
static int sprfunc(void *ptr, unsigned char letter)
|
||||
{
|
||||
struct for_snprintf *pr = (struct for_snprintf *)ptr;
|
||||
if(pr->bytes < pr->max) {
|
||||
*pr->ptr = letter;
|
||||
pr->ptr++;
|
||||
pr->bytes++;
|
||||
return true;
|
||||
}
|
||||
return false; /* filled buffer */
|
||||
}
|
||||
|
||||
|
||||
int snprintf(char *buf, size_t size, const char *fmt, ...)
|
||||
{
|
||||
int len;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, size, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
|
||||
{
|
||||
struct for_snprintf pr;
|
||||
|
||||
pr.ptr = (unsigned char *)buf;
|
||||
pr.bytes = 0;
|
||||
pr.max = size;
|
||||
|
||||
format(sprfunc, &pr, fmt, ap);
|
||||
|
||||
/* make sure it ends with a trailing zero */
|
||||
pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0';
|
||||
|
||||
return pr.bytes;
|
||||
}
|
|
@ -194,7 +194,7 @@ static const struct diac_range diac_ranges[] =
|
|||
};
|
||||
|
||||
#define MRU_MAX_LEN 32
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
bool is_diacritic(const unsigned short char_code, bool *is_rtl)
|
||||
{
|
||||
static uint8_t mru_len = 0;
|
||||
|
@ -248,4 +248,12 @@ Found:
|
|||
|
||||
return (char_code < diac->base + (info & DIAC_CNT));
|
||||
}
|
||||
|
||||
#else /*BOOTLOADER*/
|
||||
inline bool is_diacritic(const unsigned short char_code, bool *is_rtl)
|
||||
{
|
||||
(void)char_code;
|
||||
if (is_rtl)
|
||||
*is_rtl = false;
|
||||
return false;
|
||||
}
|
||||
#endif /* ndef BOOTLOADER*/
|
||||
|
|
|
@ -118,6 +118,7 @@ void LCDFN(update_viewport_rect)(int x, int y, int width, int height)
|
|||
LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height);
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
/* put a string at a given pixel position, skipping first ofs pixel columns */
|
||||
static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
|
||||
{
|
||||
|
@ -257,6 +258,72 @@ static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
|
|||
}
|
||||
font_lock(current_vp->font, false);
|
||||
}
|
||||
#else /* BOOTLOADER */
|
||||
/* put a string at a given pixel position, skipping first ofs pixel columns */
|
||||
static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
|
||||
{
|
||||
unsigned short *ucs;
|
||||
struct font* pf = font_get(current_vp->font);
|
||||
int vp_flags = current_vp->flags;
|
||||
const unsigned char *bits;
|
||||
int width;
|
||||
|
||||
if ((vp_flags & VP_FLAG_ALIGNMENT_MASK) != 0)
|
||||
{
|
||||
int w;
|
||||
|
||||
LCDFN(getstringsize)(str, &w, NULL);
|
||||
/* center takes precedence */
|
||||
if (vp_flags & VP_FLAG_ALIGN_CENTER)
|
||||
{
|
||||
x = ((current_vp->width - w)/ 2) + x;
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = current_vp->width - w - x;
|
||||
x += ofs;
|
||||
ofs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* allow utf but no diacritics or rtl lang */
|
||||
for (ucs = bidi_l2v(str, 1); *ucs; ucs++)
|
||||
{
|
||||
const unsigned short next_ch = ucs[1];
|
||||
|
||||
if (x >= current_vp->width)
|
||||
break;
|
||||
|
||||
/* Get proportional width and glyph bits */
|
||||
width = font_get_width(pf, *ucs);
|
||||
|
||||
if (ofs > width)
|
||||
{
|
||||
ofs -= width;
|
||||
continue;
|
||||
}
|
||||
|
||||
bits = font_get_bits(pf, *ucs);
|
||||
|
||||
#if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
|
||||
if (pf->depth)
|
||||
lcd_alpha_bitmap_part(bits, ofs, 0, width, x, y,
|
||||
width - ofs, pf->height);
|
||||
else
|
||||
#endif
|
||||
LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x,
|
||||
y, width - ofs, pf->height);
|
||||
if (next_ch)
|
||||
{
|
||||
x += width - ofs;
|
||||
ofs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*** pixel oriented text output ***/
|
||||
|
||||
|
|
|
@ -52,7 +52,6 @@ static const char scroll_tick_table[18] = {
|
|||
};
|
||||
|
||||
static void scroll_thread(void);
|
||||
static char scroll_stack[DEFAULT_STACK_SIZE*3];
|
||||
static const char scroll_name[] = "scroll";
|
||||
|
||||
#include "drivers/lcd-scroll.c"
|
||||
|
@ -195,8 +194,11 @@ static void scroll_thread(void)
|
|||
}
|
||||
#endif /* HAVE_REMOTE_LCD */
|
||||
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
void scroll_init(void)
|
||||
{
|
||||
static char scroll_stack[DEFAULT_STACK_SIZE*3];
|
||||
#ifdef HAVE_REMOTE_LCD
|
||||
queue_init(&scroll_queue, true);
|
||||
#endif
|
||||
|
@ -205,3 +207,9 @@ void scroll_init(void)
|
|||
IF_PRIO(, PRIORITY_USER_INTERFACE)
|
||||
IF_COP(, CPU));
|
||||
}
|
||||
#else
|
||||
void scroll_init(void)
|
||||
{
|
||||
/* DUMMY */
|
||||
}
|
||||
#endif /* ndef BOOTLOADER*/
|
||||
|
|
Loading…
Reference in a new issue