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) 2008 Dan Everton (safetydan)
11 * Copyright (C) 2018 William Wilgus
12 * String function implementations taken from dietlibc 0.31 (GPLv2 License)
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include "plugin.h"
25#define _ROCKCONF_H_ /* Protect against unwanted include */
26#include "lua.h"
27#include "lib/pluginlib_actions.h"
28
29extern long strtol(const char *nptr, char **endptr, int base);
30extern const char *strpbrk_n(const char *s, int smax, const char *accept);
31
32#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
33int errno = 0;
34#endif
35
36char *strerror(int errnum)
37{
38 (void) errnum;
39
40 DEBUGF("strerror(%d)\n", errnum);
41
42 return NULL;
43}
44
45/* splash string and allow user to scroll around
46 * provides rudimentary text reflow
47 * timeout is disabled on user interaction
48 * returns the action that caused quit
49 * [ACTION_NONE, ACTION_STD_CANCEL, ACTION_STD_OK]
50 * !ACTION_NONE (only on initial timeout)!
51 * TIMEOUT can be TIMEOUT_BLOCK or time in ticks
52*/
53int splash_scroller(int timeout, const char* str)
54{
55 if (!str)
56 str = "[nil]";
57 int w, ch_w, ch_h;
58 rb->lcd_getstringsize("W", &ch_w, &ch_h);
59
60 const int max_w = LCD_WIDTH - (ch_w * 2);
61 const int max_lines = LCD_HEIGHT / ch_h - 1;
62 const int wrap_thresh = (LCD_WIDTH / 3);
63 const char *ch;
64 const char *brk;
65
66 const int max_ch = (LCD_WIDTH / ch_w - 1) * 2;
67 char line[max_ch + 2]; /* display buffer */
68 const char break_chars[] = "@#$%^&*+-{}[]()/\\|<>:;.,? _\n\r\t";
69
70 int linepos, curline, linesdisp, realline, chars_next_break;
71 int action = ACTION_NONE;
72 int firstline = 0;
73 int cycles = 2; /* get action timeout returns immediately on first call */
74
75 while (cycles > 0)
76 {
77 /* walk whole buffer every refresh, only display relevant portion */
78 rb->lcd_clear_display();
79 curline = 0;
80 linepos = 0;
81 linesdisp = 0;
82 ch = str;
83 for (; *ch && linepos < max_ch; ch++)
84 {
85 if (ch[0] == '\t')
86 {
87 line[linepos++] = ' ';
88 line[linepos] = ' ';
89 }
90 else if (ch[0] == '\b' && timeout > 0)
91 {
92 line[linepos] = ' ';
93 rb->beep_play(1000, HZ, 1000);
94 }
95 else if (ch[0] < ' ') /* Dont copy control characters */
96 line[linepos] = (linepos == 0) ? '\0' : ' ';
97 else
98 line[linepos] = ch[0];
99
100 line[linepos + 1] = '\0'; /* terminate to check text extent */
101 rb->lcd_getstringsize(line, &w, NULL);
102
103 /* try to not split in middle of words */
104 if (w + wrap_thresh >= max_w &&
105 strpbrk_n(ch, 1, break_chars))
106 {
107 brk = strpbrk_n(ch+1, max_ch, break_chars);
108 chars_next_break = (brk - ch);
109 if (brk &&
110 (chars_next_break < 2 || w + (ch_w * chars_next_break) > max_w))
111 {
112 if (!isprint(line[linepos]))
113 {
114 line[linepos] = '\0';
115 ch--; /* back-up we want it on the next line */
116 }
117 w += max_w;
118 }
119 }
120
121 if (w > max_w ||
122 (ch[0] >= '\n' && iscntrl(ch[0])) ||
123 ch[1] == '\0')
124 {
125 realline = curline - firstline;
126 if (realline >= 0 && realline < max_lines)
127 {
128 rb->lcd_putsxy(0, realline * ch_h, line);
129 linesdisp++;
130 }
131 linepos = 0;
132 curline++;
133 continue;
134 }
135 linepos++;
136 }
137
138 rb->lcd_update();
139 if (timeout >= TIMEOUT_BLOCK)
140 {
141 action = rb->get_action(CONTEXT_STD, timeout);
142 switch(action)
143 {
144 case ACTION_STD_OK:
145 case ACTION_STD_CANCEL:
146 cycles--;
147 /* Fall Through */
148 case ACTION_NONE:
149 cycles--;
150 break;
151 case ACTION_STD_PREV:
152 timeout = TIMEOUT_BLOCK; /* disable timeout */
153 if(firstline > 0)
154 firstline--;
155 break;
156 case ACTION_STD_NEXT:
157 timeout = TIMEOUT_BLOCK; /* disable timeout */
158 if (linesdisp == max_lines)
159 firstline++;
160 break;
161 }
162 }
163 else
164 break;
165 }
166 return action;
167}
168
169long rb_pow(long x, long n)
170{
171 long pow = 1;
172 unsigned long u;
173
174 if(n <= 0)
175 {
176 if(n == 0 || x == 1)
177 return 1;
178
179 if(x != -1)
180 return x != 0 ? 1/x : 0;
181
182 n = -n;
183 }
184
185 u = n;
186 while(1)
187 {
188 if(u & 01)
189 pow *= x;
190
191 if(u >>= 1)
192 x *= x;
193 else
194 break;
195 }
196
197 return pow;
198}
199
200int strcoll(const char * str1, const char * str2)
201{
202 return rb->strcmp(str1, str2);
203}
204
205#ifndef _WIN32
206struct tm * gmtime(const time_t *timep)
207{
208 static struct tm time;
209 return rb->gmtime_r(timep, &time);
210}
211#endif
212
213int get_current_path(lua_State *L, int level)
214{
215 lua_Debug ar;
216
217 if(lua_getstack(L, level, &ar))
218 {
219 /* Try determining the base path of the current Lua chunk
220 and write it to dest. */
221 lua_getinfo(L, "S", &ar);
222
223 const char* curfile = &ar.source[1];
224 const char* pos = rb->strrchr(curfile, '/');
225 if(pos != NULL)
226 {
227 lua_pushlstring (L, curfile, pos - curfile + 1);
228 return 1;
229 }
230 }
231
232 lua_pushnil(L);
233 return 1;
234}
235
236/* filetol()
237 reads long int from an open file, skips preceding
238 whitespaces returns -1 if error, 1 on success.
239 *num set to LONG_MAX or LONG_MIN on overflow.
240 If number of digits is > than LUAI_MAXNUMBER2STR
241 filepointer will continue till the next non digit
242 but buffer will stop being filled with characters.
243 Preceding zero is ignored
244*/
245int filetol(int fd, long *num)
246{
247 static char buffer[LUAI_MAXNUMBER2STR];
248 int retn = -1;
249 char chbuf = 0;
250 size_t count = 0;
251 bool neg = false;
252 long val;
253
254 while (rb->read(fd, &chbuf, 1) == 1)
255 {
256 if(retn || !isspace(chbuf))
257 {
258 switch(chbuf)
259 {
260 case '-':
261 {
262 if (retn > 0) /* 0 preceeds, this negative sign must be in error */
263 goto get_digits;
264 neg = true;
265 continue;
266 }
267 case '0': /* strip preceeding zeros */
268 {
269 *num = 0;
270 retn = 1;
271 continue;
272 }
273 default:
274 goto get_digits;
275 }
276 }
277 }
278
279 while (rb->read(fd, &chbuf, 1) == 1)
280 {
281get_digits:
282 if(!isdigit(chbuf))
283 {
284 rb->lseek(fd, -1, SEEK_CUR);
285 break;
286 }
287 else if (count < LUAI_MAXNUMBER2STR - 2)
288 buffer[count++] = chbuf;
289 }
290
291 if(count)
292 {
293 buffer[count] = '\0';
294 val = strtol(buffer, NULL, 10);
295 *num = (neg)? -val:val;
296 retn = 1;
297 }
298
299 return retn;
300}
301
302int get_plugin_action(int timeout, bool with_remote)
303{
304 static const struct button_mapping *m1[] = { pla_main_ctx };
305 int btn;
306
307#ifndef HAVE_REMOTE_LCD
308 (void) with_remote;
309#else
310 static const struct button_mapping *m2[] = { pla_main_ctx, pla_remote_ctx };
311
312 if (with_remote)
313 btn = pluginlib_getaction(timeout, m2, 2);
314 else
315#endif
316 btn = pluginlib_getaction(timeout, m1, 1);
317
318 return btn;
319}