A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 319 lines 8.7 kB view raw
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}