make the fms update
[kugel-rb.git] / firmware / general.c
blob20b0277c09dc072ceb44ac158ac744b0b42052b8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Michael Sevakis
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "config.h"
23 #include <stdio.h>
24 #include "general.h"
26 #include "dir.h"
27 #include "limits.h"
28 #include "stdlib.h"
29 #include "string-extra.h"
30 #include "system.h"
31 #include "time.h"
32 #include "timefuncs.h"
34 #if CONFIG_CODEC == SWCODEC
35 int round_value_to_list32(unsigned long value,
36 const unsigned long list[],
37 int count,
38 bool signd)
40 unsigned long dmin = ULONG_MAX;
41 int idmin = -1, i;
43 for (i = 0; i < count; i++)
45 unsigned long diff;
47 if (list[i] == value)
49 idmin = i;
50 break;
53 if (signd ? ((long)list[i] < (long)value) : (list[i] < value))
54 diff = value - list[i];
55 else
56 diff = list[i] - value;
58 if (diff < dmin)
60 dmin = diff;
61 idmin = i;
65 return idmin;
66 } /* round_value_to_list32 */
68 /* Number of bits set in src_mask should equal src_list length */
69 int make_list_from_caps32(unsigned long src_mask,
70 const unsigned long *src_list,
71 unsigned long caps_mask,
72 unsigned long *caps_list)
74 int i, count;
75 unsigned long mask;
77 for (mask = src_mask, count = 0, i = 0;
78 mask != 0;
79 src_mask = mask, i++)
81 unsigned long test_bit;
82 mask &= mask - 1; /* Zero lowest bit set */
83 test_bit = mask ^ src_mask; /* Isolate the bit */
84 if (test_bit & caps_mask) /* Add item if caps has test bit set */
85 caps_list[count++] = src_list ? src_list[i] : (unsigned long)i;
88 return count;
89 } /* make_list_from_caps32 */
90 #endif /* CONFIG_CODEC == SWCODEC */
92 /* Create a filename with a number part in a way that the number is 1
93 * higher than the highest numbered file matching the same pattern.
94 * It is allowed that buffer and path point to the same memory location,
95 * saving a strcpy(). Path must always be given without trailing slash.
96 * "num" can point to an int specifying the number to use or NULL or a value
97 * less than zero to number automatically. The final number used will also
98 * be returned in *num. If *num is >= 0 then *num will be incremented by
99 * one. */
100 char *create_numbered_filename(char *buffer, const char *path,
101 const char *prefix, const char *suffix,
102 int numberlen IF_CNFN_NUM_(, int *num))
104 DIR *dir;
105 struct dirent *entry;
106 int max_num;
107 int pathlen;
108 int prefixlen = strlen(prefix);
109 int suffixlen = strlen(suffix);
110 char fmtstring[12];
112 if (buffer != path)
113 strlcpy(buffer, path, MAX_PATH);
115 pathlen = strlen(buffer);
117 #ifdef IF_CNFN_NUM
118 if (num && *num >= 0)
120 /* number specified */
121 max_num = *num;
123 else
124 #endif
126 /* automatic numbering */
127 max_num = 0;
129 dir = opendir(pathlen ? buffer : "/");
130 if (!dir)
131 return NULL;
133 while ((entry = readdir(dir)))
135 int curr_num, namelen;
137 if (strncasecmp((char *)entry->d_name, prefix, prefixlen))
138 continue;
140 namelen = strlen((char *)entry->d_name);
141 if ((namelen <= prefixlen + suffixlen)
142 || strcasecmp((char *)entry->d_name + namelen - suffixlen, suffix))
143 continue;
145 curr_num = atoi((char *)entry->d_name + prefixlen);
146 if (curr_num > max_num)
147 max_num = curr_num;
150 closedir(dir);
153 max_num++;
155 snprintf(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen);
156 snprintf(buffer + pathlen, MAX_PATH - pathlen, fmtstring, prefix,
157 max_num, suffix);
159 #ifdef IF_CNFN_NUM
160 if (num)
161 *num = max_num;
162 #endif
164 return buffer;
168 #if CONFIG_RTC
169 /* Create a filename with a date+time part.
170 It is allowed that buffer and path point to the same memory location,
171 saving a strcpy(). Path must always be given without trailing slash.
172 unique_time as true makes the function wait until the current time has
173 changed. */
174 char *create_datetime_filename(char *buffer, const char *path,
175 const char *prefix, const char *suffix,
176 bool unique_time)
178 struct tm *tm = get_time();
179 static struct tm last_tm;
180 int pathlen;
182 while (unique_time && !memcmp(get_time(), &last_tm, sizeof (struct tm)))
183 sleep(HZ/10);
185 last_tm = *tm;
187 if (buffer != path)
188 strlcpy(buffer, path, MAX_PATH);
190 pathlen = strlen(buffer);
191 snprintf(buffer + pathlen, MAX_PATH - pathlen,
192 "/%s%02d%02d%02d-%02d%02d%02d%s", prefix,
193 tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
194 tm->tm_hour, tm->tm_min, tm->tm_sec, suffix);
196 return buffer;
198 #endif /* CONFIG_RTC */
200 /***
201 ** Compacted pointer lists
203 ** N-length list requires N+1 elements to ensure NULL-termination.
206 /* Find a pointer in a pointer array. Returns the addess of the element if
207 * found or the address of the terminating NULL otherwise. This can be used
208 * to bounds check and add items. */
209 void ** find_array_ptr(void **arr, void *ptr)
211 void *curr;
212 for (curr = *arr; curr != NULL && curr != ptr; curr = *(++arr));
213 return arr;
216 /* Remove a pointer from a pointer array if it exists. Compacts it so that
217 * no gaps exist. Returns 0 on success and -1 if the element wasn't found. */
218 int remove_array_ptr(void **arr, void *ptr)
220 void *curr;
221 arr = find_array_ptr(arr, ptr);
223 if (*arr == NULL)
224 return -1;
226 /* Found. Slide up following items. */
229 void **arr1 = arr + 1;
230 *arr++ = curr = *arr1;
232 while (curr != NULL);
234 return 0;