1 /*
2     DeaDBeeF -- the music player
3     Copyright (C) 2009-2014 Alexey Yakovenko and other contributors
4 
5     This software is provided 'as-is', without any express or implied
6     warranty.  In no event will the authors be held liable for any damages
7     arising from the use of this software.
8 
9     Permission is granted to anyone to use this software for any purpose,
10     including commercial applications, and to alter it and redistribute it
11     freely, subject to the following restrictions:
12 
13     1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17 
18     2. Altered source versions must be plainly marked as such, and must not be
19      misrepresented as being the original software.
20 
21     3. This notice may not be removed or altered from any source distribution.
22 */
23 
24 // basic syntax:
25 // function call: $function([arg1[,arg2[,...]]])
26 // meta fields, with spaces allowed: %field name%
27 // if_defined block: [text$func()%field%more text]
28 // plain text: anywhere outside of the above
29 // escaping: $, %, [, ], \ must be escaped
30 
31 // bytecode format
32 // 0: indicates start of special block
33 //  1: function call
34 //   func_idx:byte, num_args:byte, arg1_len:byte[,arg2_len:byte[,...]]
35 //  2: meta field
36 //   len:byte, data
37 //  3: if_defined block
38 //   len:int32, data
39 //  4: pre-interpreted text
40 //   len:int32, data
41 // !0: plain text
42 
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <stdint.h>
50 #include <ctype.h>
51 #include <inttypes.h>
52 #include <math.h>
53 #include "streamer.h"
54 #include "utf8.h"
55 #include "playlist.h"
56 #include "playqueue.h"
57 #include "tf.h"
58 #include "gettext.h"
59 #include "plugins.h"
60 #include "junklib.h"
61 
62 #define min(x,y) ((x)<(y)?(x):(y))
63 
64 //#define trace(...) { fprintf(stderr, __VA_ARGS__); }
65 #define trace(fmt,...)
66 
67 typedef struct {
68     const char *i;
69     char *o;
70     int eol;
71 } tf_compiler_t;
72 
73 typedef int (*tf_func_ptr_t)(ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef);
74 
75 #define TF_MAX_FUNCS 0xff
76 
77 typedef struct {
78     const char *name;
79     tf_func_ptr_t func;
80 } tf_func_def;
81 
82 static int
83 tf_eval_int (ddb_tf_context_t *ctx, const char *code, int size, char *out, int outlen, int *bool_out, int fail_on_undef);
84 
85 #define TF_EVAL_CHECK(res, ctx, arg, arg_len, out, outlen, fail_on_undef)\
86 res = tf_eval_int (ctx, arg, arg_len, out, outlen, &bool_out, fail_on_undef);\
87 if (res < 0) { *out = 0; return -1; }
88 
89 // empty track is used when ctx.it is null
90 static playItem_t empty_track;
91 // empty playlist is used when ctx.plt is null
92 static playlist_t empty_playlist;
93 // empty code is used when "code" argumen is null
94 static char empty_code[4] = {0};
95 
96 int
tf_eval(ddb_tf_context_t * ctx,const char * code,char * out,int outlen)97 tf_eval (ddb_tf_context_t *ctx, const char *code, char *out, int outlen) {
98     if (!code) {
99         code = empty_code;
100     }
101 
102     int null_it = 0;
103     if (!ctx->it) {
104         null_it = 1;
105         ctx->it = (ddb_playItem_t *)&empty_track;
106     }
107 
108     int null_plt = 0;
109     if (!ctx->plt) {
110         null_plt = 1;
111         ctx->plt = (ddb_playlist_t *)&empty_playlist;
112     }
113 
114     int32_t codelen = *((int32_t *)code);
115     code += 4;
116     memset (out, 0, outlen);
117     int l = 0;
118 
119     int bool_out = 0;
120     int id = -1;
121     if (ctx->flags & DDB_TF_CONTEXT_HAS_ID) {
122         id = ctx->id;
123     }
124 
125     switch (id) {
126     case DB_COLUMN_FILENUMBER:
127         if (ctx->flags & DDB_TF_CONTEXT_HAS_INDEX) {
128             l = snprintf (out, outlen, "%d", ctx->idx+1);
129         }
130         else if (ctx->plt) {
131             int idx = plt_get_item_idx ((playlist_t *)ctx->plt, (playItem_t *)ctx->it, PL_MAIN);
132             l = snprintf (out, outlen, "%d", idx+1);
133         }
134         break;
135     case DB_COLUMN_PLAYING:
136         l = pl_format_item_queue ((playItem_t *)ctx->it, out, outlen);
137         break;
138     default:
139         // tf_eval_int expects outlen to not include the terminating zero
140         l = tf_eval_int (ctx, code, codelen, out, outlen-1, &bool_out, 0);
141         break;
142     }
143 
144     if (!(ctx->flags & DDB_TF_CONTEXT_MULTILINE)) {
145         for (; *out; out++) {
146             if (*out == '\n') {
147                 *out = ';';
148             }
149         }
150     }
151 
152     if (null_it) {
153         ctx->it = NULL;
154     }
155     if (null_plt) {
156         ctx->plt = NULL;
157     }
158     return l;
159 }
160 
161 // $greater(a,b) returns true if a is greater than b, otherwise false
162 int
tf_func_greater(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)163 tf_func_greater (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
164     if (argc != 2) {
165         return -1;
166     }
167     const char *arg = args;
168 
169     int bool_out = 0;
170 
171     char a[10];
172     int len;
173     TF_EVAL_CHECK(len, ctx, arg, arglens[0], a, sizeof (a), fail_on_undef);
174 
175     int aa = atoi (a);
176 
177     arg += arglens[0];
178     char b[10];
179     TF_EVAL_CHECK(len, ctx, arg, arglens[1], b, sizeof (b), fail_on_undef);
180     int bb = atoi (b);
181 
182     return aa > bb;
183 }
184 
185 // $strcmp(s1,s2) compares s1 and s2, returns true if equal, otherwise false
186 int
tf_func_strcmp(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)187 tf_func_strcmp (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
188     if (argc != 2) {
189         return -1;
190     }
191     const char *arg = args;
192 
193     int bool_out = 0;
194 
195     char s1[1000];
196     int len;
197     TF_EVAL_CHECK(len, ctx, arg, arglens[0], s1, sizeof (s1), fail_on_undef);
198 
199     arg += arglens[0];
200     char s2[1000];
201     TF_EVAL_CHECK(len, ctx, arg, arglens[1], s2, sizeof (s2), fail_on_undef);
202 
203     int res = strcmp (s1, s2);
204     return !res;
205 }
206 
207 // $num(n,len) Formats the integer number n in decimal notation with len characters. Pads with zeros
208 // from the left if necessary. len includes the dash when the number is negative. If n is not numeric, it is treated as zero.
209 int
tf_func_num(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)210 tf_func_num (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
211     const char *arg = args;
212     int bool_out = 0;
213     int len;
214 
215     if (argc != 2) {
216         return -1;
217     }
218 
219     TF_EVAL_CHECK(len, ctx, arg, arglens[0], out, outlen, fail_on_undef);
220     arg += arglens[0];
221     int n = atoi (out);
222 
223     TF_EVAL_CHECK(len, ctx, arg, arglens[1], out, outlen, fail_on_undef);
224     int n_len = atoi (out);
225 
226     if (outlen < 1 || outlen < n_len) {
227         *out = 0;
228         return -1;
229     }
230 
231     if (n_len < 0) {
232         n_len = 0;
233     }
234 
235     char *out_w = out;
236     int is_negative = n < 0;
237     int num_len = 0;
238 
239     int cnt = n;
240     do {
241         num_len++;
242         cnt /= 10;
243     } while (cnt);
244 
245     if (is_negative) {
246         *out_w++ = '-';
247         num_len++;
248         n *= -1;
249     }
250 
251     int num_len_plus_padding = num_len;
252     while (num_len_plus_padding < n_len) {
253         *out_w++ = '0';
254         num_len_plus_padding++;
255     }
256 
257     out_w += num_len - is_negative;
258     do {
259         *--out_w = (n % 10) + '0';
260         n /= 10;
261     } while (n);
262 
263     return n_len > num_len ? n_len : num_len;
264 }
265 
266 int
tf_func_abbr(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)267 tf_func_abbr (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
268     if (argc != 1 && argc != 2) {
269         return -1;
270     }
271 
272     const char *arg = args;
273 
274     int bool_out = 0;
275 
276     int len;
277     TF_EVAL_CHECK(len, ctx, arg, arglens[0], out, outlen, fail_on_undef);
278 
279     if (argc == 2) {
280         char num_chars_str[10];
281         arg += arglens[0];
282         int l;
283         TF_EVAL_CHECK(l, ctx, arg, arglens[1], num_chars_str, sizeof (num_chars_str), fail_on_undef);
284         int num_chars = atoi (num_chars_str);
285         if (len <= num_chars) {
286             return len;
287         }
288     }
289 
290     char *p = out;
291     char *pout = out;
292     const char skipchars[] = "() ,/\\|";
293     while (*p) {
294         // skip whitespace/paren
295         while (*p && strchr (skipchars, *p)) {
296             p++;
297         }
298         if (!*p) {
299             break;
300         }
301 
302         // take the first letter for abbrev
303         int is_bracket = *p == '[' || *p == ']';
304         int32_t size = 0;
305         u8_nextchar(p, &size);
306         memmove (pout, p, size);
307         pout += size;
308         p += size;
309 
310         // skip to the end of word
311         while (*p && !strchr (skipchars, *p)) {
312             if (!is_bracket) {
313                 p++;
314             }
315             else {
316                 size = 0;
317                 u8_nextchar(p, &size);
318                 memmove (pout, p, size);
319                 pout += size;
320                 p += size;
321             }
322         }
323     }
324 
325     *pout = 0;
326     return (int)(pout - out);
327 }
328 
329 int
tf_func_ansi(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)330 tf_func_ansi (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
331     if (argc != 1) {
332         return -1;
333     }
334 
335     int bool_out = 0;
336 
337     int len;
338     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
339     return len;
340 }
341 
342 int
tf_func_ascii(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)343 tf_func_ascii (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
344     if (argc != 1) {
345         return -1;
346     }
347 
348     int bool_out = 0;
349 
350     int len;
351     char temp_str[1000];
352     TF_EVAL_CHECK(len, ctx, args, arglens[0], temp_str, sizeof (temp_str), fail_on_undef);
353 
354     len = junk_iconv (temp_str, len, out, outlen, "utf-8", "ascii");
355 
356     return len;
357 }
358 
359 int
tf_caps_impl(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef,int do_lowercasing)360 tf_caps_impl (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef, int do_lowercasing) {
361     if (argc != 1) {
362         return -1;
363     }
364 
365     int bool_out = 0;
366 
367     int len;
368     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
369 
370     char *p = out;
371     char *end = p + len;
372     const char skipchars[] = "() ,/\\|";
373     while (*p) {
374         // skip whitespace/paren
375         while (*p && strchr (skipchars, *p)) {
376             p++;
377         }
378         if (!*p) {
379             break;
380         }
381 
382         int is_bracket = *p == '[' || *p == ']';
383 
384         char temp[5];
385 
386         // uppercase the first letter
387         int32_t size = 0;
388         u8_nextchar (p, &size);
389         int32_t uppersize = u8_toupper ((const signed char *)p, size, temp);
390         if (uppersize != size) {
391             memmove (p+uppersize, p+size, end-(p+size));
392             end += uppersize - size;
393             *end = 0;
394         }
395         memcpy (p, temp, uppersize);
396 
397         p += uppersize;
398 
399         // lowercase to the end of word
400         while (*p && !strchr (skipchars, *p)) {
401             if (is_bracket) {
402                 p++;
403             }
404             else {
405                 size = 0;
406                 u8_nextchar ((const char *)p, &size);
407                 if (do_lowercasing) {
408                     int32_t lowersize = u8_tolower ((const signed char *)p, size, temp);
409                     if (lowersize != size) {
410                         memmove (p+lowersize, p+size, end-(p+size));
411                         end += lowersize - size;
412                         *end = 0;
413                     }
414                     memcpy (p, temp, lowersize);
415                     p += lowersize;
416                 }
417                 else {
418                     p += size;
419                 }
420             }
421         }
422     }
423 
424     return (int)(end - out);
425 }
426 
427 int
tf_func_caps(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)428 tf_func_caps (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
429     return tf_caps_impl (ctx, argc, arglens, args, out, outlen, fail_on_undef, 1);
430 }
431 
432 int
tf_func_caps2(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)433 tf_func_caps2 (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
434     return tf_caps_impl (ctx, argc, arglens, args, out, outlen, fail_on_undef, 0);
435 }
436 
437 int
tf_func_char(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)438 tf_func_char (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
439     if (argc != 1) {
440         return -1;
441     }
442 
443     int bool_out = 0;
444 
445     int len;
446     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
447 
448     int n = atoi (out);
449     *out = 0;
450 
451     if (outlen < 5) {
452         return -1;
453     }
454     len = u8_wc_toutf8 (out, n);
455     out[len] = 0;
456     return len;
457 }
458 
459 int
tf_func_crc32(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)460 tf_func_crc32 (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
461     if (argc != 1) {
462         return -1;
463     }
464 
465     static const uint32_t tab[256] = {
466         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
467         0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
468         0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
469         0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
470         0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
471         0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
472         0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
473         0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
474         0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
475         0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
476         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
477         0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
478         0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
479         0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
480         0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
481         0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
482         0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
483         0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
484         0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
485         0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
486         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
487         0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
488         0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
489         0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
490         0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
491         0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
492         0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
493         0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
494         0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
495         0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
496         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
497         0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
498         0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
499         0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
500         0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
501         0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
502         0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
503         0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
504         0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
505         0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
506         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
507         0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
508         0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
509     };
510 
511     int bool_out = 0;
512 
513     int len;
514     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
515 
516     uint32_t crc = 0xffffffff;
517 
518     for (int i = 0; i < len; i++) {
519         crc = (crc >> 8) ^ tab[(crc ^ (uint8_t)out[i]) & 0xff];
520     }
521 
522     crc ^= 0xffffffff;
523 
524     return snprintf (out, outlen, "%u", crc);
525 }
526 
527 int
tf_func_crlf(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)528 tf_func_crlf (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
529     if (argc != 0 || outlen < 2) {
530         return -1;
531     }
532     out[0] = '\n';
533     out[1] = 0;
534     return 1;
535 }
536 
537 // $left(text,n) returns the first n characters of text
538 int
tf_func_left(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)539 tf_func_left (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
540     if (argc != 2) {
541         return -1;
542     }
543     const char *arg = args;
544 
545     int bool_out = 0;
546 
547     // get number of characters
548     char num_chars_str[10];
549     arg += arglens[0];
550     int len;
551     TF_EVAL_CHECK(len, ctx, arg, arglens[1], num_chars_str, sizeof (num_chars_str), fail_on_undef);
552     int num_chars = atoi (num_chars_str);
553     if (num_chars <= 0 || num_chars > outlen) {
554         *out = 0;
555         return -1;
556     }
557 
558     // get text
559     char text[1000];
560     arg = args;
561     TF_EVAL_CHECK(len, ctx, arg, arglens[0], text, sizeof (text), fail_on_undef);
562 
563     int res = u8_strncpy (out, text, num_chars);
564     trace ("left: (%s,%d) -> (%s), res: %d\n", text, num_chars, out, res);
565     return res;
566 }
567 
568 int
tf_func_directory(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)569 tf_func_directory (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
570     if (argc < 1 || argc > 2) {
571         return -1;
572     }
573 
574     int bool_out = 0;
575 
576     int len;
577     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
578 
579     int path_len = len;
580 
581     int levels = 1;
582     if (argc == 2) {
583         char temp[20];
584         args += arglens[0];
585         TF_EVAL_CHECK(len, ctx, args, arglens[1], temp, sizeof (temp), fail_on_undef);
586         levels = atoi (temp);
587         if (levels < 0) {
588             return -1;
589         }
590     }
591 
592     char *end = out + path_len - 1;
593     char *start = end;
594 
595     while (levels--) {
596         // get to the last delimiter
597         while (end >= out && *end != '/') {
598             end--;
599         }
600 
601         if (end < out) {
602             *out = 0;
603             return -1;
604         }
605 
606         // skip multiple delimiters
607         while (end >= out && *end == '/') {
608             end--;
609         }
610         end++;
611 
612         if (end < out) {
613             *out = 0;
614             return -1;
615         }
616 
617         // find another delimiter
618         start = end - 1;
619         while (start > out && *start != '/') {
620             start--;
621         }
622 
623         if (*start == '/') {
624             start++;
625         }
626 
627         if (levels) {
628             end = start;
629             while (end >= out && *end == '/') {
630                 end--;
631             }
632         }
633     }
634 
635     memmove (out, start, end-start);
636     out[end-start] = 0;
637     return (int)(end-start);
638 }
639 
640 int
tf_func_directory_path(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)641 tf_func_directory_path (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
642     if (argc < 1 || argc > 2) {
643         return -1;
644     }
645 
646     int bool_out = 0;
647 
648     int len;
649     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
650 
651     char *p = out + len - 1;
652 
653     while (p >= out && *p != '/') {
654         p--;
655     }
656     while (p >= out && *p == '/') {
657         p--;
658     }
659     if (p < out) {
660         *out = 0;
661         return -1;
662     }
663 
664     p++;
665     *p = 0;
666     return (int)(p-out);
667 }
668 
669 int
tf_func_ext(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)670 tf_func_ext (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
671     if (argc < 1 || argc > 2) {
672         return -1;
673     }
674 
675     int bool_out = 0;
676 
677     int len;
678     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
679 
680     char *e = out + len;
681     char *c = e - 1;
682     char *p = NULL;
683 
684     while (c >= out && *c != '/') {
685         if (*c == '.') {
686             p = c+1;
687             break;
688         }
689         c--;
690     }
691 
692     if (!p) {
693         *out = 0;
694         return 0;
695     }
696 
697     memmove (out, p, e-p+1);
698     return (int)(e-p);
699 }
700 
701 int
tf_func_filename(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)702 tf_func_filename (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
703     if (argc < 1 || argc > 2) {
704         return -1;
705     }
706 
707     int bool_out = 0;
708 
709     int len;
710     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
711 
712     char *e = out + len;
713     char *p = e - 1;
714     while (p >= out && *p != '/') {
715         p--;
716     }
717 
718     p++;
719 
720     memmove (out, p, e-p+1);
721     return (int)(e-p);
722 }
723 
724 int
tf_func_add(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)725 tf_func_add (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
726     int bool_out = 0;
727 
728     int outval = 0;
729     const char *arg = args;
730     for (int i = 0; i < argc; i++) {
731         int len;
732         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
733         outval += atoi (out);
734         arg += arglens[i];
735     }
736     return snprintf (out, outlen, "%d", outval);
737 }
738 
739 int
tf_func_div(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)740 tf_func_div (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
741     int bool_out = 0;
742 
743     if (argc < 2) {
744         return -1;
745     }
746 
747     float outval = 0;
748     const char *arg = args;
749     for (int i = 0; i < argc; i++) {
750         int len;
751         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
752         if (i == 0) {
753             outval = atoi (out);
754         }
755         else {
756             int divider = atoi (out);
757             if (divider == 0) {
758                 out[0] = 0;
759                 return -1;
760             }
761             outval /= divider;
762         }
763         arg += arglens[i];
764     }
765     int res = snprintf (out, outlen, "%d", (int)round (outval));
766     return res;
767 }
768 
769 int
tf_func_max(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)770 tf_func_max (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
771     int bool_out = 0;
772 
773     if (argc == 0) {
774         return -1;
775     }
776 
777     int nmax = -1;
778     const char *arg = args;
779     for (int i = 0; i < argc; i++) {
780         int len;
781         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
782         int n = atoi (out);
783         if (n > nmax) {
784             nmax = n;
785         }
786         arg += arglens[i];
787     }
788     int res = snprintf (out, outlen, "%d", nmax);
789     return res;
790 }
791 
792 int
tf_func_min(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)793 tf_func_min (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
794     int bool_out = 0;
795 
796     if (argc == 0) {
797         return -1;
798     }
799 
800     int nmin = 0x7fffffff;
801     const char *arg = args;
802     for (int i = 0; i < argc; i++) {
803         int len;
804         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
805         int n = atoi (out);
806         if (n < nmin) {
807             nmin = n;
808         }
809         arg += arglens[i];
810     }
811     int res = snprintf (out, outlen, "%d", nmin);
812     return res;
813 }
814 
815 int
tf_func_mod(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)816 tf_func_mod (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
817     int bool_out = 0;
818 
819     if (argc < 2) {
820         return -1;
821     }
822 
823     int outval = 0;
824     const char *arg = args;
825     for (int i = 0; i < argc; i++) {
826         int len;
827         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
828         if (i == 0) {
829             outval = atoi (out);
830         }
831         else {
832             int divider = atoi (out);
833             if (divider == 0) {
834                 *out = 0;
835                 return -1;
836             }
837             outval %= divider;
838         }
839         arg += arglens[i];
840     }
841     int res = snprintf (out, outlen, "%d", outval);
842     return res;
843 }
844 
845 int
tf_func_mul(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)846 tf_func_mul (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
847     int bool_out = 0;
848 
849     if (argc < 2) {
850         return -1;
851     }
852 
853     int outval = 0;
854     const char *arg = args;
855     for (int i = 0; i < argc; i++) {
856         int len;
857         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
858         if (i == 0) {
859             outval = atoi (out);
860         }
861         else {
862             outval *= atoi (out);
863         }
864         arg += arglens[i];
865     }
866     int res = snprintf (out, outlen, "%d", outval);
867     return res;
868 }
869 
870 int
tf_func_muldiv(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)871 tf_func_muldiv (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
872     int bool_out = 0;
873 
874     if (argc != 3) {
875         return -1;
876     }
877 
878     int vals[3];
879     const char *arg = args;
880     for (int i = 0; i < argc; i++) {
881         int len;
882         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
883         vals[i] = atoi (out);
884         arg += arglens[i];
885     }
886 
887     if (vals[2] == 0) {
888         *out = 0;
889         return -1;
890     }
891 
892     int outval = (int)round(vals[0] * vals[1] / (float)vals[2]);
893 
894     int res = snprintf (out, outlen, "%d", outval);
895     return res;
896 }
897 
898 int
tf_func_rand(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)899 tf_func_rand (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
900     if (argc != 0) {
901         return -1;
902     }
903 
904     int outval = rand ();
905 
906     int res = snprintf (out, outlen, "%d", outval);
907     return res;
908 }
909 
910 int
tf_func_sub(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)911 tf_func_sub (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
912     int bool_out = 0;
913 
914     if (argc < 2) {
915         return -1;
916     }
917 
918     int outval = 0;
919     const char *arg = args;
920     for (int i = 0; i < argc; i++) {
921         int len;
922         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
923         if (i == 0) {
924             outval = atoi (out);
925         }
926         else {
927             outval -= atoi (out);
928         }
929         arg += arglens[i];
930     }
931     int res = snprintf (out, outlen, "%d", outval);
932     return res;
933 }
934 
935 int
tf_func_if(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)936 tf_func_if (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
937     if (argc < 2 || argc > 3) {
938         return -1;
939     }
940     int bool_out = 0;
941 
942     const char *arg = args;
943     int res;
944     TF_EVAL_CHECK(res, ctx, arg, arglens[0], out, outlen, fail_on_undef);
945     arg += arglens[0];
946     if (bool_out) {
947         trace ("condition true, eval then block\n");
948         TF_EVAL_CHECK(res, ctx, arg, arglens[1], out, outlen, fail_on_undef);
949     }
950     else if (argc == 3) {
951         trace ("condition false, eval else block\n");
952         arg += arglens[1];
953         TF_EVAL_CHECK(res, ctx, arg, arglens[2], out, outlen, fail_on_undef);
954     }
955 
956     return res;
957 }
958 
959 int
tf_func_if2(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)960 tf_func_if2 (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
961     if (argc != 2) {
962         return -1;
963     }
964     int bool_out = 0;
965 
966     const char *arg = args;
967     int res;
968     TF_EVAL_CHECK(res, ctx, arg, arglens[0], out, outlen, fail_on_undef);
969     arg += arglens[0];
970     if (bool_out) {
971         return res;
972     }
973     else {
974         TF_EVAL_CHECK(res, ctx, arg, arglens[1], out, outlen, fail_on_undef);
975     }
976 
977     return res;
978 }
979 
980 int
tf_func_if3(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)981 tf_func_if3 (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
982     if (argc < 2) {
983         return -1;
984     }
985     int bool_out = 0;
986 
987     const char *arg = args;
988     for (int i = 0; i < argc; i++) {
989         int res;
990         TF_EVAL_CHECK(res, ctx, arg, arglens[i], out, outlen, fail_on_undef);
991         arg += arglens[i];
992         if (bool_out || i == argc-1) {
993             return res;
994         }
995     }
996     *out = 0;
997     return -1;
998 }
999 
1000 int
tf_func_ifequal(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1001 tf_func_ifequal (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1002     if (argc != 4) {
1003         return -1;
1004     }
1005 
1006     int bool_out = 0;
1007 
1008     const char *arg = args;
1009     int len;
1010     TF_EVAL_CHECK(len, ctx, arg, arglens[0], out, outlen, fail_on_undef);
1011 
1012     int arg1 = atoi (out);
1013 
1014     arg += arglens[0];
1015     TF_EVAL_CHECK(len, ctx, arg, arglens[1], out, outlen, fail_on_undef);
1016 
1017     int arg2 = atoi (out);
1018 
1019     arg += arglens[1];
1020 
1021     int idx = 2;
1022     if (arg1 != arg2) {
1023         arg += arglens[2];
1024         idx = 3;
1025     }
1026 
1027     TF_EVAL_CHECK(len, ctx, arg, arglens[idx], out, outlen, fail_on_undef);
1028     return len;
1029 }
1030 
1031 int
tf_func_ifgreater(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1032 tf_func_ifgreater (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1033     if (argc != 4) {
1034         return -1;
1035     }
1036 
1037     int bool_out = 0;
1038 
1039     const char *arg = args;
1040     int len;
1041     TF_EVAL_CHECK(len, ctx, arg, arglens[0], out, outlen, fail_on_undef);
1042 
1043     int arg1 = atoi (out);
1044 
1045     arg += arglens[0];
1046     TF_EVAL_CHECK(len, ctx, arg, arglens[1], out, outlen, fail_on_undef);
1047 
1048     int arg2 = atoi (out);
1049 
1050     arg += arglens[1];
1051 
1052     int idx = 2;
1053     if (arg1 <= arg2) {
1054         arg += arglens[2];
1055         idx = 3;
1056     }
1057 
1058     TF_EVAL_CHECK(len, ctx, arg, arglens[idx], out, outlen, fail_on_undef);
1059     return len;
1060 }
1061 
1062 int
tf_func_iflonger(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1063 tf_func_iflonger (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1064     if (argc != 4) {
1065         return -1;
1066     }
1067 
1068     int bool_out = 0;
1069 
1070     const char *arg = args;
1071     int len;
1072     TF_EVAL_CHECK(len, ctx, arg, arglens[0], out, outlen, fail_on_undef);
1073     int l1 = (int)strlen (out);
1074 
1075     arg += arglens[0];
1076     TF_EVAL_CHECK(len, ctx, arg, arglens[1], out, outlen, fail_on_undef);
1077     int l2 = (int)strlen (out);
1078 
1079     arg += arglens[1];
1080     int idx = 2;
1081     if (l1 <= l2) {
1082         arg += arglens[2];
1083         idx = 3;
1084     }
1085 
1086     TF_EVAL_CHECK(len, ctx, arg, arglens[idx], out, outlen, fail_on_undef);
1087     return len;
1088 }
1089 
1090 int
tf_func_select(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1091 tf_func_select (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1092     if (argc < 3) {
1093         return -1;
1094     }
1095 
1096     const char *arg = args;
1097 
1098     int bool_out = 0;
1099 
1100     int res;
1101     TF_EVAL_CHECK(res, ctx, arg, arglens[0], out, outlen, fail_on_undef);
1102 
1103     int n = atoi (out);
1104     if (n < 1 || n >= argc) {
1105         return 0;
1106     }
1107 
1108     arg += arglens[0];
1109 
1110     for (int i = 1; i < n; i++) {
1111         arg += arglens[i];
1112     }
1113     TF_EVAL_CHECK(res, ctx, arg, arglens[n], out, outlen, fail_on_undef);
1114     return res;
1115 }
1116 
1117 static void
tf_append_out(char ** out,int * out_len,const char * in,int in_len)1118 tf_append_out (char **out, int *out_len, const char *in, int in_len) {
1119     in_len = min (in_len, *out_len);
1120     in_len = u8_strnbcpy (*out, in, in_len);
1121     *out_len -= in_len;
1122     *out += in_len;
1123 }
1124 
1125 int
tf_func_meta(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1126 tf_func_meta (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1127     if (argc != 1) {
1128         return -1;
1129     }
1130 
1131     if (!ctx->it) {
1132         return 0;
1133     }
1134 
1135     int bool_out = 0;
1136 
1137     const char *arg = args;
1138     int len;
1139     TF_EVAL_CHECK(len, ctx, arg, arglens[0], out, outlen, fail_on_undef);
1140 
1141     const char *meta = pl_find_meta_raw ((playItem_t *)ctx->it, out);
1142     if (!meta) {
1143         return 0;
1144     }
1145 
1146     return u8_strnbcpy(out, meta, outlen);
1147 }
1148 
1149 const char *
tf_get_channels_string_for_track(playItem_t * it)1150 tf_get_channels_string_for_track (playItem_t *it) {
1151     const char *val = pl_find_meta_raw (it, ":CHANNELS");
1152     if (val) {
1153         int ch = atoi (val);
1154         if (ch == 1) {
1155             val = _("mono");
1156         }
1157         else if (ch == 2) {
1158             val = _("stereo");
1159         }
1160     }
1161     else {
1162         val = _("stereo");
1163     }
1164     return val;
1165 }
1166 
1167 int
tf_func_channels(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1168 tf_func_channels (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1169     if (argc != 0) {
1170         return -1;
1171     }
1172 
1173     if (!ctx->it) {
1174         return 0;
1175     }
1176 
1177     const char *val = tf_get_channels_string_for_track ((playItem_t *)ctx->it);
1178     return u8_strnbcpy(out, val, outlen);
1179 }
1180 
1181 // Boolean
1182 int
tf_func_and(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1183 tf_func_and (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1184     int bool_out = 0;
1185 
1186     const char *arg = args;
1187     for (int i = 0; i < argc; i++) {
1188         int len;
1189         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
1190         if (!bool_out) {
1191             return 0;
1192         }
1193         arg += arglens[i];
1194     }
1195     *out = 0;
1196     return 1;
1197 }
1198 
1199 int
tf_func_or(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1200 tf_func_or (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1201     int bool_out = 0;
1202 
1203     const char *arg = args;
1204     for (int i = 0; i < argc; i++) {
1205         int len;
1206         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
1207         if (bool_out) {
1208             return 1;
1209         }
1210         arg += arglens[i];
1211     }
1212     *out = 0;
1213     return 0;
1214 }
1215 
1216 int
tf_func_not(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1217 tf_func_not (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1218     if (argc != 1) {
1219         return -1;
1220     }
1221     int bool_out = 0;
1222 
1223     int len;
1224     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
1225     return !bool_out;
1226 }
1227 
1228 int
tf_func_xor(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1229 tf_func_xor (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1230     int bool_out = 0;
1231     int result = 0;
1232 
1233     const char *arg = args;
1234     for (int i = 0; i < argc; i++) {
1235         int len;
1236         TF_EVAL_CHECK(len, ctx, arg, arglens[i], out, outlen, fail_on_undef);
1237         if (i == 0) {
1238             result = bool_out;
1239         }
1240         else {
1241             result ^= bool_out;
1242         }
1243         arg += arglens[i];
1244     }
1245     *out = 0;
1246     return result;
1247 }
1248 
1249 int
tf_func_fix_eol(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1250 tf_func_fix_eol (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1251     if (argc != 1 && argc != 2) {
1252         return -1;
1253     }
1254 
1255     int bool_out = 0;
1256 
1257     int len;
1258 
1259     char *p = out;
1260     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
1261 
1262     char ind[1000];
1263     int indlen = sizeof (ind);
1264     if (argc == 2) {
1265         TF_EVAL_CHECK(indlen, ctx, args + arglens[0], arglens[1], ind, indlen, fail_on_undef);
1266     }
1267     else {
1268         strcpy (ind, " (...)");
1269         indlen = (int)strlen (ind);
1270     }
1271 
1272     for (int n = 0; n < len; n++, p++) {
1273         if (*p == '\n') {
1274             if (outlen-n < indlen) {
1275                 *out = 0;
1276                 return -1;
1277             }
1278             memcpy (p, ind, indlen);
1279             len = n + indlen;
1280             break;
1281         }
1282     }
1283 
1284     return len;
1285 }
1286 
1287 int
tf_func_hex(ddb_tf_context_t * ctx,int argc,const char * arglens,const char * args,char * out,int outlen,int fail_on_undef)1288 tf_func_hex (ddb_tf_context_t *ctx, int argc, const char *arglens, const char *args, char *out, int outlen, int fail_on_undef) {
1289     if (argc != 1 && argc != 2) {
1290         return -1;
1291     }
1292 
1293     int bool_out = 0;
1294 
1295     int len;
1296 
1297     TF_EVAL_CHECK(len, ctx, args, arglens[0], out, outlen, fail_on_undef);
1298     int num = atoi (out);
1299     int pad = 0;
1300     *out = 0;
1301 
1302     if (argc == 2) {
1303         TF_EVAL_CHECK(len, ctx, args + arglens[0], arglens[1], out, outlen, fail_on_undef);
1304         if (!isdigit (*out)) {
1305             *out = 0;
1306             return -1;
1307         }
1308         pad = atoi (out);
1309         *out = 0;
1310     }
1311 
1312     int n = num;
1313     int cnt = 0;
1314     do {
1315         n >>= 4;
1316         cnt++;
1317     } while (n);
1318 
1319     char *p = out;
1320 
1321     if (pad > outlen || cnt > outlen) {
1322         return -1;
1323     }
1324 
1325     if (pad > cnt) {
1326         for (n = 0; n < pad-cnt; n++, p++) {
1327             *p = '0';
1328         }
1329     }
1330     p += cnt;
1331     *p-- = 0;
1332 
1333     n = num;
1334 
1335     const char hex[] = "0123456789abcdef";
1336 
1337     do {
1338         *p-- = hex[n & 0x0f];
1339         n >>= 4;
1340     } while (n);
1341 
1342     return (int)strlen (out);
1343 }
1344 
1345 tf_func_def tf_funcs[TF_MAX_FUNCS] = {
1346     // Control flow
1347     { "if", tf_func_if },
1348     { "if2", tf_func_if2 },
1349     { "if3", tf_func_if3 },
1350     { "ifequal", tf_func_ifequal },
1351     { "ifgreater", tf_func_ifgreater },
1352     { "iflonger", tf_func_iflonger },
1353     { "select", tf_func_select },
1354     // Arithmetic
1355     { "add", tf_func_add },
1356     { "div", tf_func_div },
1357     { "greater", tf_func_greater },
1358     { "max", tf_func_max },
1359     { "min", tf_func_min },
1360     { "mod", tf_func_mod },
1361     { "mul", tf_func_mul },
1362     { "muldiv", tf_func_muldiv },
1363     { "rand", tf_func_rand },
1364     { "sub", tf_func_sub },
1365     // Boolean
1366     { "and", tf_func_and },
1367     { "or", tf_func_or },
1368     { "not", tf_func_not },
1369     { "xor", tf_func_xor },
1370     // String
1371     { "abbr", tf_func_abbr },
1372     { "ansi", tf_func_ansi },
1373     { "ascii", tf_func_ascii },
1374     { "caps", tf_func_caps },
1375     { "caps2", tf_func_caps2 },
1376     { "char", tf_func_char },
1377     { "crc32", tf_func_crc32 },
1378     { "crlf", tf_func_crlf },
1379     { "cut", tf_func_left },
1380     { "left", tf_func_left }, // alias of 'cut'
1381     { "directory", tf_func_directory },
1382     { "directory_path", tf_func_directory_path },
1383     { "ext", tf_func_ext },
1384     { "filename", tf_func_filename },
1385     { "fix_eol", tf_func_fix_eol },
1386     { "hex", tf_func_hex },
1387     { "strcmp", tf_func_strcmp },
1388     { "num", tf_func_num },
1389     // Track info
1390     { "meta", tf_func_meta },
1391     { "channels", tf_func_channels },
1392     { NULL, NULL }
1393 };
1394 
1395 static int
tf_eval_int(ddb_tf_context_t * ctx,const char * code,int size,char * out,int outlen,int * bool_out,int fail_on_undef)1396 tf_eval_int (ddb_tf_context_t *ctx, const char *code, int size, char *out, int outlen, int *bool_out, int fail_on_undef) {
1397     playItem_t *it = (playItem_t *)ctx->it;
1398     char *init_out = out;
1399     *bool_out = 0;
1400     while (size) {
1401         if (*code) {
1402             int len = u8_charcpy (out, code, outlen);
1403             if (len == 0) {
1404                 break;
1405             }
1406             code += len;
1407             size -= len;
1408             out += len;
1409             outlen -= len;
1410         }
1411         else {
1412             code++;
1413             size--;
1414             if (*code == 1) {
1415                 code++;
1416                 size--;
1417                 tf_func_ptr_t func = tf_funcs[*code].func;
1418                 code++;
1419                 size--;
1420                 int res = func (ctx, code[0], code+1, code+1+code[0], out, outlen, fail_on_undef);
1421                 if (res == -1) {
1422                     return -1;
1423                 }
1424                 if (res > 0) {
1425                     *bool_out = 1;
1426                     // hack for returning true + empty string result (e.g. tf_func_and)
1427                     if (*out == 0) {
1428                         res = 0;
1429                     }
1430                 }
1431 
1432                 out += res;
1433                 outlen -= res;
1434 
1435                 int blocksize = 1 + code[0];
1436                 for (int i = 0; i < code[0]; i++) {
1437                     blocksize += code[1+i];
1438                 }
1439                 code += blocksize;
1440                 size -= blocksize;
1441             }
1442             else if (*code == 2) {
1443                 code++;
1444                 size--;
1445                 uint8_t len = *code;
1446                 code++;
1447                 size--;
1448 
1449                 char name[len+1];
1450                 memcpy (name, code, len);
1451                 name[len] = 0;
1452 
1453                 // special cases
1454                 // most if not all of this stuff is to make tf scripts
1455                 // compatible with fb2k syntax
1456                 pl_lock ();
1457                 const char *val = NULL;
1458                 const char *aa_fields[] = { "album artist", "albumartist", "band", "artist", "composer", "performer", NULL };
1459                 const char *a_fields[] = { "artist", "album artist", "albumartist", "composer", "performer", NULL };
1460                 const char *alb_fields[] = { "album", "venue", NULL };
1461 
1462                 // set to 1 if special case handler successfully wrote the output
1463                 int skip_out = 0;
1464 
1465                 // temp vars used for strcmp optimizations
1466                 int tmp_a = 0, tmp_b = 0, tmp_c = 0, tmp_d = 0;
1467 
1468                 if (!strcmp (name, aa_fields[0])) {
1469                     for (int i = 0; !val && aa_fields[i]; i++) {
1470                         val = pl_find_meta_raw (it, aa_fields[i]);
1471                     }
1472                 }
1473                 else if (!strcmp (name, a_fields[0])) {
1474                     for (int i = 0; !val && a_fields[i]; i++) {
1475                         val = pl_find_meta_raw (it, a_fields[i]);
1476                     }
1477                 }
1478                 else if (!strcmp (name, "album")) {
1479                     for (int i = 0; !val && alb_fields[i]; i++) {
1480                         val = pl_find_meta_raw (it, alb_fields[i]);
1481                     }
1482                 }
1483                 else if (!strcmp (name, "track artist")) {
1484                     const char *aa = NULL;
1485                     for (int i = 0; !val && aa_fields[i]; i++) {
1486                         val = pl_find_meta_raw (it, aa_fields[i]);
1487                     }
1488                     aa = val;
1489                     val = NULL;
1490                     for (int i = 0; !val && a_fields[i]; i++) {
1491                         val = pl_find_meta_raw (it, a_fields[i]);
1492                     }
1493                     if (val && aa && !strcmp (val, aa)) {
1494                         val = NULL;
1495                     }
1496                 }
1497                 else if (!strcmp (name, "tracknumber")) {
1498                     const char *v = pl_find_meta_raw (it, "track");
1499                     if (v) {
1500                         const char *p = v;
1501                         while (*p) {
1502                             if (!isdigit (*p)) {
1503                                 break;
1504                             }
1505                             p++;
1506                         }
1507                         if (p > v) {
1508                             int len = snprintf (out, outlen, "%02d", atoi(v));
1509                             out += len;
1510                             outlen -= len;
1511                             skip_out = 1;
1512                         }
1513                     }
1514                 }
1515                 else if (!strcmp (name, "title")) {
1516                     val = pl_find_meta_raw (it, "title");
1517                     if (!val) {
1518                         const char *v = pl_find_meta_raw (it, ":URI");
1519                         if (v) {
1520                             const char *start = strrchr (v, '/');
1521                             if (start) {
1522                                 start++;
1523                             }
1524                             else {
1525                                 start = v;
1526                             }
1527                             const char *end = strrchr (start, '.');
1528                             if (end) {
1529                                 int n = (int)(end-start);
1530                                 n = min ((int)(end-start), outlen);
1531                                 n = u8_strnbcpy (out, start, n);
1532                                 outlen -= n;
1533                                 out += n;
1534                             }
1535                         }
1536                     }
1537                 }
1538                 else if (!strcmp (name, "discnumber")) {
1539                     val = pl_find_meta_raw (it, "disc");
1540                 }
1541                 else if (!strcmp (name, "totaldiscs")) {
1542                     val = pl_find_meta_raw (it, "numdiscs");
1543                 }
1544                 else if (!strcmp (name, "track number")) {
1545                     const char *v = pl_find_meta_raw (it, "track");
1546                     if (v) {
1547                         const char *p = v;
1548                         while (*p) {
1549                             if (!isdigit (*p)) {
1550                                 break;
1551                             }
1552                             p++;
1553                         }
1554                         if (p > v) {
1555                             int len = snprintf (out, outlen, "%d", atoi(v));
1556                             out += len;
1557                             outlen -= len;
1558                             skip_out = 1;
1559                         }
1560                     }
1561                 }
1562                 else if (!strcmp (name, "date")) {
1563                     // NOTE: foobar2000 uses "date" instead of "year"
1564                     // so for %date% we simply return the content of "year"
1565                     val = pl_find_meta_raw (it, "year");
1566                 }
1567                 else if (!strcmp (name, "samplerate")) {
1568                     val = pl_find_meta_raw (it, ":SAMPLERATE");
1569                 }
1570                 else if (!strcmp (name, "bitrate")) {
1571                     val = pl_find_meta_raw (it, ":BITRATE");
1572                 }
1573                 else if (!strcmp (name, "filesize")) {
1574                     val = pl_find_meta_raw (it, ":FILE_SIZE");
1575                 }
1576                 else if (!strcmp (name, "filesize_natural")) {
1577                     const char *v = pl_find_meta_raw (it, ":FILE_SIZE");
1578                     if (v) {
1579                         int64_t bs = atoll (v);
1580                         int len;
1581                         if (bs >= 1024*1024*1024) {
1582                             double gb = (double)bs / (double)(1024*1024*1024);
1583                             len = snprintf (out, outlen, "%.3lf GB", gb);
1584                         }
1585                         else if (bs >= 1024*1024) {
1586                             double mb = (double)bs / (double)(1024*1024);
1587                             len = snprintf (out, outlen, "%.3lf MB", mb);
1588                         }
1589                         else if (bs >= 1024) {
1590                             double kb = (double)bs / (double)(1024);
1591                             len = snprintf (out, outlen, "%.3lf KB", kb);
1592                         }
1593                         else {
1594                             len = snprintf (out, outlen, "%lld B", bs);
1595                         }
1596                         out += len;
1597                         outlen -= len;
1598                         skip_out = 1;
1599                     }
1600                 }
1601                 else if (!strcmp (name, "channels")) {
1602                     val = tf_get_channels_string_for_track (it);
1603                 }
1604                 else if (!strcmp (name, "codec")) {
1605                     val = pl_find_meta_raw (it, ":FILETYPE");
1606                 }
1607                 else if (!strcmp (name, "replaygain_album_gain")) {
1608                     val = pl_find_meta_raw (it, ":REPLAYGAIN_ALBUMGAIN");
1609                 }
1610                 else if (!strcmp (name, "replaygain_album_peak")) {
1611                     val = pl_find_meta_raw (it, ":REPLAYGAIN_ALBUMPEAK");
1612                 }
1613                 else if (!strcmp (name, "replaygain_track_gain")) {
1614                     val = pl_find_meta_raw (it, ":REPLAYGAIN_TRACKGAIN");
1615                 }
1616                 else if (!strcmp (name, "replaygain_track_peak")) {
1617                     val = pl_find_meta_raw (it, ":REPLAYGAIN_TRACKPEAK");
1618                 }
1619                 else if ((tmp_a = !strcmp (name, "playback_time")) || (tmp_b = !strcmp (name, "playback_time_seconds")) || (tmp_c = !strcmp (name, "playback_time_remaining")) || (tmp_d = !strcmp (name, "playback_time_remaining_seconds"))) {
1620                     playItem_t *playing = streamer_get_playing_track ();
1621                     if (it && playing == it && !(ctx->flags & DDB_TF_CONTEXT_NO_DYNAMIC)) {
1622                         float t = streamer_get_playpos ();
1623                         if (tmp_c || tmp_d) {
1624                             printf ("inverse time %d %d %d %d\n", tmp_a, tmp_b, tmp_c, tmp_d);
1625                             float dur = pl_get_item_duration (it);
1626                             t = dur - t;
1627                         }
1628                         if (t >= 0) {
1629                             int len = 0;
1630                             if (tmp_a || tmp_c) {
1631                                 int hr = t/3600;
1632                                 int mn = (t-hr*3600)/60;
1633                                 int sc = t-hr*3600-mn*60;
1634                                 if (hr) {
1635                                     len = snprintf (out, outlen, "%d:%02d:%02d", hr, mn, sc);
1636                                 }
1637                                 else {
1638                                     len = snprintf (out, outlen, "%d:%02d", mn, sc);
1639                                 }
1640                             }
1641                             else if (tmp_b || tmp_d) {
1642                                 len = snprintf (out, outlen, "%0.2f", t);
1643                             }
1644                             out += len;
1645                             outlen -= len;
1646                             skip_out = 1;
1647                             // notify the caller about update interval
1648                             if (!ctx->update || (ctx->update > 1000)) {
1649                                 ctx->update = 1000;
1650                             }
1651                         }
1652                     }
1653                     if (playing) {
1654                         pl_item_unref (playing);
1655                     }
1656                 }
1657                 else if ((tmp_a = !strcmp (name, "length")) || (tmp_b = !strcmp (name, "length_ex"))) {
1658                     float t = pl_get_item_duration (it);
1659                     if (tmp_a) {
1660                         t = roundf (t);
1661                     }
1662                     else if (tmp_b) {
1663                         t = roundf(t * 1000) / 1000.f;
1664                     }
1665                     if (t >= 0) {
1666                         int hr = t/3600;
1667                         int mn = (t-hr*3600)/60;
1668                         int sc = tmp_a ? t-hr*3600-mn*60 : t-hr*3600-mn*60;
1669                         int ms = tmp_b ? (t-hr*3600-mn*60-sc) * 1000.f : 0;
1670                         int len = 0;
1671                         if (tmp_a) {
1672                             if (hr) {
1673                                 len = snprintf (out, outlen, "%d:%02d:%02d", hr, mn, sc);
1674                             }
1675                             else {
1676                                 len = snprintf (out, outlen, "%d:%02d", mn, sc);
1677                             }
1678                         }
1679                         else if (tmp_b) {
1680                             if (hr) {
1681                                 len = snprintf (out, outlen, "%d:%02d:%02d.%03d", hr, mn, sc, ms);
1682                             }
1683                             else {
1684                                 len = snprintf (out, outlen, "%d:%02d.%03d", mn, sc, ms);
1685                             }
1686                         }
1687                         out += len;
1688                         outlen -= len;
1689                         skip_out = 1;
1690                     }
1691                 }
1692                 else if ((tmp_a = !strcmp (name, "length_seconds") || (tmp_b = !strcmp (name, "length_seconds_fp")))) {
1693                     float t = pl_get_item_duration (it);
1694                     if (t >= 0) {
1695                         int len;
1696                         if (tmp_a) {
1697                             len = snprintf (out, outlen, "%d", (int)roundf(t));
1698                         }
1699                         else {
1700                             len = snprintf (out, outlen, "%0.3f", t);
1701                         }
1702                         out += len;
1703                         outlen -= len;
1704                         skip_out = 1;
1705                     }
1706                 }
1707                 else if (!strcmp (name, "length_samples")) {
1708                     int len = snprintf (out, outlen, "%d", ctx->it->endsample - ctx->it->startsample);
1709                     out += len;
1710                     outlen -= len;
1711                     skip_out = 1;
1712                 }
1713                 else if ((tmp_a = !strcmp (name, "isplaying")) || (tmp_b = !strcmp (name, "ispaused"))) {
1714                     playItem_t *playing = streamer_get_playing_track ();
1715 
1716                     if (playing &&
1717                             (
1718                             (tmp_a && plug_get_output ()->state () == OUTPUT_STATE_PLAYING)
1719                             || (tmp_b && plug_get_output ()->state () == OUTPUT_STATE_PAUSED)
1720                             )) {
1721                         *out++ = '1';
1722                         outlen--;
1723                         skip_out = 1;
1724                     }
1725                     if (playing) {
1726                         pl_item_unref (playing);
1727                     }
1728                 }
1729                 else if (!strcmp (name, "filename")) {
1730                     const char *v = pl_find_meta_raw (it, ":URI");
1731                     if (v) {
1732                         const char *start = strrchr (v, '/');
1733                         if (start) {
1734                             start++;
1735                         }
1736                         else {
1737                             start = v;
1738                         }
1739                         const char *end = strrchr (start, '.');
1740                         if (end) {
1741                             tf_append_out(&out, &outlen, start, (int)(end-start));
1742                             skip_out = 1;
1743                         }
1744                     }
1745                 }
1746                 else if (!strcmp (name, "filename_ext")) {
1747                     const char *v = pl_find_meta_raw (it, ":URI");
1748                     if (v) {
1749                         const char *start = strrchr (v, '/');
1750                         if (start) {
1751                             tf_append_out (&out, &outlen, start+1, (int)strlen (start+1));
1752                             skip_out = 1;
1753                         }
1754                     }
1755                 }
1756                 else if (!strcmp (name, "directoryname")) {
1757                     const char *v = pl_find_meta_raw (it, ":URI");
1758                     if (v) {
1759                         const char *end = strrchr (v, '/');
1760                         if (end) {
1761                             const char *start = end - 1;
1762                             while (start >= v && *start != '/') {
1763                                 start--;
1764                             }
1765                             if (start && start != end) {
1766                                 start++;
1767                                 tf_append_out(&out, &outlen, start, (int)(end-start));
1768                                 skip_out = 1;
1769                             }
1770                         }
1771                     }
1772                 }
1773                 else if (!strcmp (name, "path")) {
1774                     val = pl_find_meta_raw (it, ":URI");
1775                 }
1776                 // index of track in playlist (zero-padded)
1777                 else if (!strcmp (name, "list_index")) {
1778                     if (it) {
1779                         int total_tracks = plt_get_item_count ((playlist_t *)ctx->plt, ctx->iter);
1780                         int digits = 0;
1781                         do {
1782                             total_tracks /= 10;
1783                             digits++;
1784                         } while (total_tracks);
1785 
1786                         int idx = 0;
1787                         if (ctx->flags & DDB_TF_CONTEXT_HAS_INDEX) {
1788                             idx = ctx->idx + 1;
1789                         }
1790                         else {
1791                             idx = pl_get_idx_of_iter (it, ctx->iter) + 1;
1792                         }
1793                         int len = snprintf (out, outlen, "%0*d", digits, idx);
1794                         out += len;
1795                         outlen -= len;
1796                         skip_out = 1;
1797                     }
1798                 }
1799                 // total number of tracks in playlist
1800                 else if (!strcmp (name, "list_total")) {
1801                     int total_tracks = -1;
1802                     if (ctx->plt) {
1803                         total_tracks = plt_get_item_count ((playlist_t *)ctx->plt, ctx->iter);
1804                     }
1805                     else {
1806                         playlist_t *plt = plt_get_curr ();
1807                         if (plt) {
1808                             total_tracks = plt_get_item_count (plt, ctx->iter);
1809                             plt_unref (plt);
1810                         }
1811                     }
1812                     if (total_tracks >= 0) {
1813                         int len = snprintf (out, outlen, "%d", total_tracks);
1814                         out += len;
1815                         outlen -= len;
1816                         skip_out = 1;
1817                     }
1818                 }
1819                 // index of track in queue
1820                 else if (!strcmp (name, "queue_index")) {
1821                     if (it) {
1822                         int idx = playqueue_test (it) + 1;
1823                         if (idx >= 1) {
1824                             int len = snprintf (out, outlen, "%d", idx);
1825                             out += len;
1826                             outlen -= len;
1827                             skip_out = 1;
1828                         }
1829                     }
1830                 }
1831                 // indexes of track in queue
1832                 else if (!strcmp (name, "queue_indexes")) {
1833                     if (it) {
1834                         int idx = playqueue_test (it) + 1;
1835                         if (idx >= 1) {
1836                             int len = snprintf (out, outlen, "%d", idx);
1837                             out += len;
1838                             outlen -= len;
1839                             int count = playqueue_getcount ();
1840                             for (int i = idx; i < count; i++) {
1841                                 playItem_t *trk = playqueue_get_item (i);
1842                                 if (trk) {
1843                                     if (it == trk) {
1844                                         len = snprintf (out, outlen, ",%d", i + 1);
1845                                         out += len;
1846                                         outlen -= len;
1847                                     }
1848                                     pl_item_unref (trk);
1849                                 }
1850                             }
1851                             skip_out = 1;
1852                         }
1853                     }
1854                 }
1855                 // total amount of tracks in queue
1856                 else if (!strcmp (name, "queue_total")) {
1857                     int count = playqueue_getcount ();
1858                     if (count >= 0) {
1859                         int len = snprintf (out, outlen, "%d", count);
1860                         out += len;
1861                         outlen -= len;
1862                         skip_out = 1;
1863                     }
1864                 }
1865                 else if (!strcmp (name, "_deadbeef_version")) {
1866                     val = VERSION;
1867                 }
1868                 else {
1869                     val = pl_find_meta_raw (it, name);
1870                 }
1871 
1872                 if (val || (!val && out > init_out)) {
1873                     *bool_out = 1;
1874                 }
1875 
1876                 // default case
1877                 if (!skip_out && val) {
1878                     int32_t l = u8_strnbcpy (out, val, outlen);
1879 
1880                     // replace any \n with ; for display
1881                     char *p = out;
1882                     while (p < out + l) {
1883                         if (*p == '\n') {
1884                             //*p = ';';
1885                         }
1886                         p++;
1887                     }
1888 
1889                     out += l;
1890                     outlen -= l;
1891                 }
1892                 pl_unlock ();
1893                 if (!skip_out && !val && fail_on_undef) {
1894                     return -1;
1895                 }
1896 
1897                 code += len;
1898                 size -= len;
1899             }
1900             else if (*code == 3) {
1901                 code++;
1902                 size--;
1903                 int32_t len;
1904                 memcpy (&len, code, 4);
1905                 code += 4;
1906                 size -= 4;
1907 
1908                 int bool_out = 0;
1909                 int res = tf_eval_int (ctx, code, len, out, outlen, &bool_out, 1);
1910                 if (res > 0) {
1911                     out += res;
1912                     outlen -= res;
1913                 }
1914                 else if (res < 0 && fail_on_undef) {
1915                     return res;
1916                 }
1917                 code += len;
1918                 size -= len;
1919             }
1920             else if (*code == 4) {
1921                 code++;
1922                 size--;
1923                 int32_t len;
1924                 memcpy (&len, code, 4);
1925                 code += 4;
1926                 size -= 4;
1927                 int32_t l = u8_strnbcpy(out, code, len);
1928                 out += l;
1929                 outlen -= l;
1930                 code += len;
1931                 size -= len;
1932             }
1933             else {
1934                 return -1;
1935             }
1936         }
1937     }
1938     *out = 0;
1939     return (int)(out-init_out);
1940 }
1941 
1942 int
1943 tf_compile_plain (tf_compiler_t *c);
1944 
1945 int
tf_compile_func(tf_compiler_t * c)1946 tf_compile_func (tf_compiler_t *c) {
1947     c->i++;
1948 
1949     // function marker
1950     *(c->o++) = 0;
1951     *(c->o++) = 1;
1952 
1953     const char *name_start = c->i;
1954 
1955     // find opening (
1956     while (*(c->i) && *(c->i) != '(') {
1957         c->i++;
1958     }
1959 
1960     if (!*(c->i)) {
1961         return -1;
1962     }
1963 
1964     int i;
1965     for (i = 0; tf_funcs[i].name; i++) {
1966         int l = (int)strlen (tf_funcs[i].name);
1967         if (c->i - name_start == l && !memcmp (tf_funcs[i].name, name_start, l)) {
1968             *(c->o++) = i;
1969             break;
1970         }
1971     }
1972     if (!tf_funcs[i].name) {
1973         return -1;
1974     }
1975 
1976     char func_name[c->i - name_start + 1];
1977     memcpy (func_name, name_start, c->i-name_start);
1978     func_name[c->i-name_start] = 0;
1979 
1980     c->i++;
1981 
1982     // remember ptr and start reading args
1983     char *start = c->o;
1984     *(c->o++) = 0; // num args
1985     char *argstart = c->o;
1986 
1987     //parse comma separated args until )
1988     while (*(c->i)) {
1989         if (*(c->i) == ',' || *(c->i) == ')') {
1990             // next arg
1991             int len = (int)(c->o - argstart);
1992 
1993             // special case for empty argument list
1994             if (len == 0 && *(c->i) == ')' && (*start) == 0) {
1995                 break;
1996             }
1997 
1998             // expand arg lengths buffer by 1
1999             memmove (start+(*start)+2, start+(*start)+1, c->o - start - (*start));
2000             c->o++;
2001             (*start)++; // num args++
2002             // store arg length
2003             start[*start] = len;
2004             argstart = c->o;
2005 
2006             if (*(c->i) == ')') {
2007                 break;
2008             }
2009             c->i++;
2010         }
2011         else if (tf_compile_plain (c)) {
2012             return -1;
2013         }
2014     }
2015     if (*(c->i) != ')') {
2016         return -1;
2017     }
2018     c->i++;
2019 
2020     return 0;
2021 }
2022 
2023 int
tf_compile_field(tf_compiler_t * c)2024 tf_compile_field (tf_compiler_t *c) {
2025     c->i++;
2026     *(c->o++) = 0;
2027     *(c->o++) = 2;
2028 
2029     const char *fstart = c->i;
2030     char *plen = c->o;
2031     c->o += 1;
2032     while (*(c->i)) {
2033         if (*(c->i) == '%') {
2034             break;
2035         }
2036         else {
2037             *(c->o++) = *(c->i++);
2038         }
2039     }
2040     if (*(c->i) != '%') {
2041         return -1;
2042     }
2043     c->i++;
2044 
2045     int32_t len = (int32_t)(c->o - plen - 1);
2046     if (len > 0xff) {
2047         return -1;
2048     }
2049     *plen = len;
2050 
2051     char field[len+1];
2052     memcpy (field, fstart, len);
2053     field[len] = 0;
2054     return 0;
2055 }
2056 
2057 int
tf_compile_ifdef(tf_compiler_t * c)2058 tf_compile_ifdef (tf_compiler_t *c) {
2059     c->i++;
2060     *(c->o++) = 0;
2061     *(c->o++) = 3;
2062 
2063     char *plen = c->o;
2064     c->o += 4;
2065 
2066     char *start = c->o;
2067 
2068     while (*(c->i)) {
2069         if (*(c->i) == '\\') {
2070             c->i++;
2071             if (*(c->i) != 0) {
2072                 *(c->o++) = *(c->i++);
2073             }
2074         }
2075         else if (*(c->i) == ']') {
2076             break;
2077         }
2078         else if (tf_compile_plain (c)) {
2079             return -1;
2080         }
2081     }
2082 
2083     if (*(c->i) != ']') {
2084         return -1;
2085     }
2086     c->i++;
2087 
2088     int32_t len = (int32_t)(c->o - plen - 4);
2089     memcpy (plen, &len, 4);
2090 
2091     char value[len+1];
2092     memcpy (value, start, len);
2093     value[len] = 0;
2094     return 0;
2095 }
2096 
2097 int
tf_compile_plain(tf_compiler_t * c)2098 tf_compile_plain (tf_compiler_t *c) {
2099     int eol = c->eol;
2100     c->eol = 0;
2101     char i = *(c->i);
2102     if (i == '$') {
2103         if (c->i[1] == '$') {
2104             c->i++;
2105             *(c->o++) = *(c->i++);
2106         }
2107         else if (tf_compile_func (c)) {
2108             return -1;
2109         }
2110     }
2111     else if (i == '[') {
2112         if (tf_compile_ifdef (c)) {
2113             return -1;
2114         }
2115     }
2116     else if (i == '%') {
2117         if (c->i[1] == '%') {
2118             c->i++;
2119             *(c->o++) = *(c->i++);
2120             return 0;
2121         }
2122         if (tf_compile_field (c)) {
2123             return -1;
2124         }
2125     }
2126     // FIXME this is not fb2k spec
2127     else if (*(c->i) == '\\') {
2128         c->i++;
2129         if (*(c->i) != 0) {
2130             *(c->o++) = *(c->i++);
2131         }
2132     }
2133     else if (eol && i == '/' && c->i[1] == '/') {
2134         // skip to end of line
2135         while (c->i[0] && c->i[0] != '\n') {
2136             c->i++;
2137         }
2138         c->eol = 1;
2139     }
2140     else if (i == '\'') {
2141         // copy as plain text to next single-quote
2142         c->i++;
2143 
2144         if (c->i[0] == '\'') {
2145             *(c->o++) = *(c->i++);
2146         }
2147         else {
2148             while (c->i[0] && c->i[0] != '\'') {
2149                 *(c->o++) = *(c->i++);
2150             }
2151             if (c->i[0] == '\'') {
2152                 c->i++;
2153             }
2154         }
2155     }
2156     else if (i == '\n') {
2157         c->i++;
2158         c->eol = 1;
2159     }
2160     else {
2161         *(c->o++) = *(c->i++);
2162     }
2163     return 0;
2164 }
2165 
2166 char *
tf_compile(const char * script)2167 tf_compile (const char *script) {
2168     tf_compiler_t c;
2169     memset (&c, 0, sizeof (c));
2170 
2171     c.i = script;
2172 
2173     char code[strlen(script) * 3];
2174     memset (code, 0, sizeof (code));
2175 
2176     c.o = code;
2177 
2178     c.eol = 1;
2179 
2180     while (*(c.i)) {
2181         if (tf_compile_plain (&c)) {
2182             return NULL;
2183         }
2184     }
2185 
2186     size_t size = c.o - code;
2187     char *out = malloc (size + 8);
2188     memcpy (out + 4, code, size);
2189     memset (out + 4 + size, 0, 4); // FIXME: this is the padding for possible buffer overflow bug fix
2190     *((int32_t *)out) = (int32_t)(size);
2191     return out;
2192 }
2193 
2194 void
tf_free(char * code)2195 tf_free (char *code) {
2196     free (code);
2197 }
2198 
2199 void
tf_import_legacy(const char * fmt,char * out,int outsize)2200 tf_import_legacy (const char *fmt, char *out, int outsize) {
2201     while (*fmt && outsize > 1) {
2202         if (*fmt == '\'' || *fmt == '$') {
2203             if (outsize < 3) {
2204                 break;
2205             }
2206             *out++ = *fmt;
2207             *out++ = *fmt++;
2208             outsize -= 2;
2209         }
2210         else if (*fmt == '\n') {
2211             if (outsize < 7) {
2212                 break;
2213             }
2214             strcpy (out, "$crlf()");
2215             out += 7;
2216             outsize -= 7;
2217             fmt++;
2218         }
2219         else if (*fmt == '[') {
2220             if (outsize < 3) {
2221                 break;
2222             }
2223             strcpy (out, "'['");
2224             out += 3;
2225             outsize -= 3;
2226             fmt++;
2227         }
2228         else if (*fmt == ']') {
2229             if (outsize < 3) {
2230                 break;
2231             }
2232             strcpy (out, "']'");
2233             out += 3;
2234             outsize -= 3;
2235             fmt++;
2236         }
2237         else if (*fmt != '%') {
2238             *out++ = *fmt++;
2239             outsize--;
2240         }
2241         else {
2242             fmt++;
2243             if (!*fmt) {
2244                 break;
2245             }
2246             if (*fmt == '@') {
2247                 const char *e = fmt;
2248                 e++;
2249                 while (*e && *e != '@') {
2250                     e++;
2251                 }
2252 #define APPEND(x) {size_t size = strlen (x); if (size >= outsize-1) break; memcpy (out, x, size); out += size; outsize -= size;}
2253                 if (*e == '@') {
2254                     char nm[100];
2255                     size_t l = e-fmt-1;
2256                     l = min (l, sizeof (nm)-1);
2257                     strncpy (nm+1, fmt+1, l);
2258                     nm[l+2] = 0;
2259                     nm[0] = '%';
2260                     nm[l+1] = '%';
2261 
2262                     APPEND (nm);
2263                     fmt = e+1;
2264                 }
2265                 continue;
2266             }
2267             else if (*fmt == 'a') {
2268                 APPEND ("%artist%");
2269             }
2270             else if (*fmt == 't') {
2271                 APPEND ("%title%");
2272             }
2273             else if (*fmt == 'b') {
2274                 APPEND ("%album%");
2275             }
2276             else if (*fmt == 'B') {
2277                 APPEND ("%album artist%");
2278             }
2279             else if (*fmt == 'C') {
2280                 APPEND ("%composer%");
2281             }
2282             else if (*fmt == 'n') {
2283                 APPEND ("%tracknumber%");
2284             }
2285             else if (*fmt == 'N') {
2286                 APPEND ("%numtracks%");
2287             }
2288             else if (*fmt == 'y') {
2289                 APPEND ("%date%");
2290             }
2291             else if (*fmt == 'Y') {
2292                 APPEND ("%original_release_time%");
2293             }
2294             else if (*fmt == 'g') {
2295                 APPEND ("%genre%");
2296             }
2297             else if (*fmt == 'c') {
2298                 APPEND ("%comment%");
2299             }
2300             else if (*fmt == 'r') {
2301                 APPEND ("%copyright%");
2302             }
2303             else if (*fmt == 'l') {
2304                 APPEND ("%length%");
2305             }
2306             else if (*fmt == 'e') {
2307                 APPEND ("%playback_time%");
2308             }
2309             else if (*fmt == 'f') {
2310                 APPEND ("%filename_ext%");
2311             }
2312             else if (*fmt == 'F') {
2313                 APPEND ("%_path_raw%");
2314             }
2315             else if (*fmt == 'T') {
2316                 APPEND ("$info(tagtype)");
2317             }
2318             else if (*fmt == 'd') {
2319                 APPEND ("%directoryname%");
2320             }
2321             else if (*fmt == 'D') {
2322                 APPEND ("$directory_path(%_path_raw%)");
2323             }
2324             else if (*fmt == 'L') {
2325                 APPEND ("%list_length%"); // TODO
2326             }
2327             else if (*fmt == 'X') {
2328                 APPEND ("%list_selected%"); // TODO
2329             }
2330             else if (*fmt == 'Z') {
2331                 APPEND ("$channels()");
2332             }
2333             else if (*fmt == 'V') {
2334                 APPEND ("%_deadbeef_version%");
2335             }
2336             else if (*fmt == '%') {
2337                 APPEND ("%%");
2338             }
2339             else {
2340                 *out++ = *fmt;
2341                 outsize--;
2342             }
2343 #undef APPEND
2344             fmt++;
2345         }
2346     }
2347     *out = 0;
2348 }
2349