aced667f48
The new vuprintf makes unnecessary workarounds due to formatting limitations. I checked grep output for whatever appeared to fit but it's possible I missed some instances because they weren't so obvious. Also, this means sound settings can dynamically work with any number of decimals rather than the current assumption of one or two. Add an ipow() function to help and take advantage of dynamic field width and precision. Consolidate string formatting of sound settings. Change-Id: I46caf534859dfd1916cd440cd25e5206b192fcd8
233 lines
6.5 KiB
C
233 lines
6.5 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2006 by Michael Sevakis
|
|
*
|
|
* 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 <stdio.h>
|
|
#include "kernel.h"
|
|
#include "general.h"
|
|
#include "file.h"
|
|
#include "dir.h"
|
|
#include "rbpaths.h"
|
|
#include "limits.h"
|
|
#include "stdlib.h"
|
|
#include "string-extra.h"
|
|
#include "time.h"
|
|
#include "timefuncs.h"
|
|
|
|
#if CONFIG_CODEC == SWCODEC
|
|
int round_value_to_list32(unsigned long value,
|
|
const unsigned long list[],
|
|
int count,
|
|
bool signd)
|
|
{
|
|
unsigned long dmin = ULONG_MAX;
|
|
int idmin = -1, i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
unsigned long diff;
|
|
|
|
if (list[i] == value)
|
|
{
|
|
idmin = i;
|
|
break;
|
|
}
|
|
|
|
if (signd ? ((long)list[i] < (long)value) : (list[i] < value))
|
|
diff = value - list[i];
|
|
else
|
|
diff = list[i] - value;
|
|
|
|
if (diff < dmin)
|
|
{
|
|
dmin = diff;
|
|
idmin = i;
|
|
}
|
|
}
|
|
|
|
return idmin;
|
|
} /* round_value_to_list32 */
|
|
|
|
/* Number of bits set in src_mask should equal src_list length */
|
|
int make_list_from_caps32(unsigned long src_mask,
|
|
const unsigned long *src_list,
|
|
unsigned long caps_mask,
|
|
unsigned long *caps_list)
|
|
{
|
|
int i, count;
|
|
unsigned long mask;
|
|
|
|
for (mask = src_mask, count = 0, i = 0;
|
|
mask != 0;
|
|
src_mask = mask, i++)
|
|
{
|
|
unsigned long test_bit;
|
|
mask &= mask - 1; /* Zero lowest bit set */
|
|
test_bit = mask ^ src_mask; /* Isolate the bit */
|
|
if (test_bit & caps_mask) /* Add item if caps has test bit set */
|
|
caps_list[count++] = src_list ? src_list[i] : (unsigned long)i;
|
|
}
|
|
|
|
return count;
|
|
} /* make_list_from_caps32 */
|
|
#endif /* CONFIG_CODEC == SWCODEC */
|
|
|
|
/* Create a filename with a number part in a way that the number is 1
|
|
* higher than the highest numbered file matching the same pattern.
|
|
* It is allowed that buffer and path point to the same memory location,
|
|
* saving a strcpy(). Path must always be given without trailing slash.
|
|
* "num" can point to an int specifying the number to use or NULL or a value
|
|
* less than zero to number automatically. The final number used will also
|
|
* be returned in *num. If *num is >= 0 then *num will be incremented by
|
|
* one. */
|
|
char *create_numbered_filename(char *buffer, const char *path,
|
|
const char *prefix, const char *suffix,
|
|
int numberlen IF_CNFN_NUM_(, int *num))
|
|
{
|
|
DIR *dir;
|
|
struct dirent *entry;
|
|
int max_num;
|
|
int pathlen;
|
|
int prefixlen = strlen(prefix);
|
|
int suffixlen = strlen(suffix);
|
|
|
|
if (buffer != path)
|
|
strlcpy(buffer, path, MAX_PATH);
|
|
|
|
pathlen = strlen(buffer);
|
|
|
|
#ifdef IF_CNFN_NUM
|
|
if (num && *num >= 0)
|
|
{
|
|
/* number specified */
|
|
max_num = *num;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
/* automatic numbering */
|
|
max_num = 0;
|
|
|
|
dir = opendir(pathlen ? buffer : HOME_DIR);
|
|
if (!dir)
|
|
return NULL;
|
|
|
|
while ((entry = readdir(dir)))
|
|
{
|
|
int curr_num, namelen;
|
|
|
|
if (strncasecmp((char *)entry->d_name, prefix, prefixlen))
|
|
continue;
|
|
|
|
namelen = strlen((char *)entry->d_name);
|
|
if ((namelen <= prefixlen + suffixlen)
|
|
|| strcasecmp((char *)entry->d_name + namelen - suffixlen, suffix))
|
|
continue;
|
|
|
|
curr_num = atoi((char *)entry->d_name + prefixlen);
|
|
if (curr_num > max_num)
|
|
max_num = curr_num;
|
|
}
|
|
|
|
closedir(dir);
|
|
}
|
|
|
|
max_num++;
|
|
|
|
snprintf(buffer + pathlen, MAX_PATH - pathlen, "/%s%0*d%s", prefix,
|
|
numberlen, max_num, suffix);
|
|
|
|
#ifdef IF_CNFN_NUM
|
|
if (num)
|
|
*num = max_num;
|
|
#endif
|
|
|
|
return buffer;
|
|
}
|
|
|
|
|
|
#if CONFIG_RTC
|
|
/* Create a filename with a date+time part.
|
|
It is allowed that buffer and path point to the same memory location,
|
|
saving a strcpy(). Path must always be given without trailing slash.
|
|
unique_time as true makes the function wait until the current time has
|
|
changed. */
|
|
char *create_datetime_filename(char *buffer, const char *path,
|
|
const char *prefix, const char *suffix,
|
|
bool unique_time)
|
|
{
|
|
struct tm *tm = get_time();
|
|
static struct tm last_tm;
|
|
int pathlen;
|
|
|
|
while (unique_time && !memcmp(get_time(), &last_tm, sizeof (struct tm)))
|
|
sleep(HZ/10);
|
|
|
|
last_tm = *tm;
|
|
|
|
if (buffer != path)
|
|
strlcpy(buffer, path, MAX_PATH);
|
|
|
|
pathlen = strlen(buffer);
|
|
snprintf(buffer + pathlen, MAX_PATH - pathlen,
|
|
"/%s%02d%02d%02d-%02d%02d%02d%s", prefix,
|
|
tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
|
|
tm->tm_hour, tm->tm_min, tm->tm_sec, suffix);
|
|
|
|
return buffer;
|
|
}
|
|
#endif /* CONFIG_RTC */
|
|
|
|
/***
|
|
** Compacted pointer lists
|
|
**
|
|
** N-length list requires N+1 elements to ensure NULL-termination.
|
|
**/
|
|
|
|
/* Find a pointer in a pointer array. Returns the addess of the element if
|
|
* found or the address of the terminating NULL otherwise. This can be used
|
|
* to bounds check and add items. */
|
|
void ** find_array_ptr(void **arr, void *ptr)
|
|
{
|
|
void *curr;
|
|
for (curr = *arr; curr != NULL && curr != ptr; curr = *(++arr));
|
|
return arr;
|
|
}
|
|
|
|
/* Remove a pointer from a pointer array if it exists. Compacts it so that
|
|
* no gaps exist. Returns 0 on success and -1 if the element wasn't found. */
|
|
int remove_array_ptr(void **arr, void *ptr)
|
|
{
|
|
void *curr;
|
|
arr = find_array_ptr(arr, ptr);
|
|
|
|
if (*arr == NULL)
|
|
return -1;
|
|
|
|
/* Found. Slide up following items. */
|
|
do
|
|
{
|
|
void **arr1 = arr + 1;
|
|
*arr++ = curr = *arr1;
|
|
}
|
|
while (curr != NULL);
|
|
|
|
return 0;
|
|
}
|