A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Michael Sevakis
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include "kernel.h"
24#include "general.h"
25#include "file.h"
26#include "dir.h"
27#include "rbpaths.h"
28#include "limits.h"
29#include "stdlib.h"
30#include "string-extra.h"
31#include "time.h"
32#include "timefuncs.h"
33
34int round_value_to_list32(unsigned long value,
35 const unsigned long list[],
36 int count,
37 bool signd)
38{
39 unsigned long dmin = ULONG_MAX;
40 int idmin = -1, i;
41
42 for (i = 0; i < count; i++)
43 {
44 unsigned long diff;
45
46 if (list[i] == value)
47 {
48 idmin = i;
49 break;
50 }
51
52 if (signd ? ((long)list[i] < (long)value) : (list[i] < value))
53 diff = value - list[i];
54 else
55 diff = list[i] - value;
56
57 if (diff < dmin)
58 {
59 dmin = diff;
60 idmin = i;
61 }
62 }
63
64 return idmin;
65} /* round_value_to_list32 */
66
67/* Number of bits set in src_mask should equal src_list length */
68int make_list_from_caps32(unsigned long src_mask,
69 const unsigned long *src_list,
70 unsigned long caps_mask,
71 unsigned long *caps_list)
72{
73 int i, count;
74 unsigned long mask;
75
76 for (mask = src_mask, count = 0, i = 0;
77 mask != 0;
78 src_mask = mask, i++)
79 {
80 unsigned long test_bit;
81 mask &= mask - 1; /* Zero lowest bit set */
82 test_bit = mask ^ src_mask; /* Isolate the bit */
83 if (test_bit & caps_mask) /* Add item if caps has test bit set */
84 caps_list[count++] = src_list ? src_list[i] : (unsigned long)i;
85 }
86
87 return count;
88} /* make_list_from_caps32 */
89
90/* Create a filename with a number part in a way that the number is 1
91 * higher than the highest numbered file matching the same pattern.
92 * It is allowed that buffer and path point to the same memory location,
93 * saving a strcpy(). Path must always be given without trailing slash.
94 * "num" can point to an int specifying the number to use or NULL or a value
95 * less than zero to number automatically. The final number used will also
96 * be returned in *num. If *num is >= 0 then *num will be incremented by
97 * one. */
98char *create_numbered_filename(char *buffer, const char *path,
99 const char *prefix, const char *suffix,
100 int numberlen IF_CNFN_NUM_(, int *num))
101{
102 DIR *dir;
103 struct dirent *entry;
104 int max_num;
105 int pathlen;
106 int prefixlen = strlen(prefix);
107 int suffixlen = strlen(suffix);
108
109 if (buffer != path)
110 strmemccpy(buffer, path, MAX_PATH);
111
112 pathlen = strlen(buffer);
113
114#ifdef IF_CNFN_NUM
115 if (num && *num >= 0)
116 {
117 /* number specified */
118 max_num = *num;
119 }
120 else
121#endif
122 {
123 /* automatic numbering */
124 max_num = 0;
125
126 dir = opendir(pathlen ? buffer : HOME_DIR);
127 if (!dir)
128 return NULL;
129
130 while ((entry = readdir(dir)))
131 {
132 int curr_num, namelen;
133
134 if (strncasecmp((char *)entry->d_name, prefix, prefixlen))
135 continue;
136
137 namelen = strlen((char *)entry->d_name);
138 if ((namelen <= prefixlen + suffixlen)
139 || strcasecmp((char *)entry->d_name + namelen - suffixlen, suffix))
140 continue;
141
142 curr_num = atoi((char *)entry->d_name + prefixlen);
143 if (curr_num > max_num)
144 max_num = curr_num;
145 }
146
147 closedir(dir);
148 }
149
150 max_num++;
151
152 snprintf(buffer + pathlen, MAX_PATH - pathlen, "/%s%0*d%s", prefix,
153 numberlen, max_num, suffix);
154
155#ifdef IF_CNFN_NUM
156 if (num)
157 *num = max_num;
158#endif
159
160 return buffer;
161}
162
163
164#if CONFIG_RTC
165/* Create a filename with a date+time part.
166 It is allowed that buffer and path point to the same memory location,
167 saving a strcpy(). Path must always be given without trailing slash.
168 unique_time as true makes the function wait until the current time has
169 changed. */
170char *create_datetime_filename(char *buffer, const char *path,
171 const char *prefix, const char *suffix,
172 bool unique_time)
173{
174 struct tm *tm = get_time();
175 static struct tm last_tm;
176 int pathlen;
177
178 while (unique_time && !memcmp(get_time(), &last_tm, sizeof (struct tm)))
179 sleep(HZ/10);
180
181 last_tm = *tm;
182
183 if (buffer != path)
184 strmemccpy(buffer, path, MAX_PATH);
185
186 pathlen = strlen(buffer);
187 snprintf(buffer + pathlen, MAX_PATH - pathlen,
188 "/%s%02d%02d%02d-%02d%02d%02d%s", prefix,
189 tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
190 tm->tm_hour, tm->tm_min, tm->tm_sec, suffix);
191
192 return buffer;
193}
194#endif /* CONFIG_RTC */
195
196/***
197 ** Compacted pointer lists
198 **
199 ** N-length list requires N+1 elements to ensure NULL-termination.
200 **/
201
202/* Find a pointer in a pointer array. Returns the addess of the element if
203 * found or the address of the terminating NULL otherwise. This can be used
204 * to bounds check and add items. */
205void ** find_array_ptr(void **arr, void *ptr)
206{
207 void *curr;
208 for (curr = *arr; curr != NULL && curr != ptr; curr = *(++arr));
209 return arr;
210}
211
212/* Remove a pointer from a pointer array if it exists. Compacts it so that
213 * no gaps exist. Returns 0 on success and -1 if the element wasn't found. */
214int remove_array_ptr(void **arr, void *ptr)
215{
216 void *curr;
217 arr = find_array_ptr(arr, ptr);
218
219 if (*arr == NULL)
220 return -1;
221
222 /* Found. Slide up following items. */
223 do
224 {
225 void **arr1 = arr + 1;
226 *arr++ = curr = *arr1;
227 }
228 while (curr != NULL);
229
230 return 0;
231}