rockbox/firmware/general.c
Thomas Martitz 382d1861af kernel: Break out kernel primitives into separate files and move to separate dir.
No code changed, just shuffling stuff around. This should make it easier to
build only select parts kernel and use different implementations.

Change-Id: Ie1f00f93008833ce38419d760afd70062c5e22b5
2014-03-03 18:11:57 +01:00

235 lines
6.6 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);
char fmtstring[12];
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(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen);
snprintf(buffer + pathlen, MAX_PATH - pathlen, fmtstring, prefix,
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;
}