Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
tuple_compiler.c
Go to the documentation of this file.
1 /*
2  * tuple_compiler.c
3  * Copyright (c) 2007 Matti 'ccr' Hämäläinen
4  * Copyright (c) 2011 John Lindgren
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions, and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions, and the following disclaimer in the documentation
14  * provided with the distribution.
15  *
16  * This software is provided "as is" and without any warranty, express or
17  * implied. In no event shall the authors be liable for any damages arising from
18  * the use of this software.
19  */
20 
21 /*
22  * TODO:
23  * - Unicode/UTF-8 support in format strings. using any non-ASCII
24  * characters in Tuplez format strings WILL cause things go boom
25  * at the moment!
26  *
27  * - implement definitions (${=foo,"baz"} ${=foo,1234})
28  * - implement functions
29  * - implement handling of external expressions
30  * - evaluation context: how local variables should REALLY work?
31  * currently there is just a single context, is a "global" context needed?
32  */
33 
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 
40 #include <glib.h>
41 
42 #include "tuple_compiler.h"
43 
44 #define MAX_STR (256)
45 #define MIN_ALLOC_NODES (8)
46 #define MIN_ALLOC_BUF (64)
47 #define TUPLEZ_MAX_VARS (4)
48 
49 #define tuple_error(ctx, ...) fprintf (stderr, "Tuple compiler: " __VA_ARGS__)
50 
51 enum {
52  OP_RAW = 0, /* plain text */
53  OP_FIELD, /* a field/variable */
62 };
63 
64 enum {
67 };
68 
70  int opcode; /* operator, see OP_ enums */
71  int var[TUPLEZ_MAX_VARS]; /* tuple variable references */
72  char *text; /* raw text, if any (OP_RAW) */
73  struct _TupleEvalNode *children, *next, *prev; /* children of this struct, and pointer to next node. */
74 };
75 
76 typedef struct {
77  char *name;
78  int type; /* Type of variable, see VAR_* */
79  int defvali;
80  TupleValueType ctype; /* Type of constant/def value */
81 
82  int fieldidx; /* if >= 0: Index # of "pre-defined" Tuple fields */
83  bool_t fieldread, fieldvalid;
84  char * fieldstr;
85 } TupleEvalVar;
86 
90 };
91 
92 
94 {
95  g_free(var->name);
96  str_unref (var->fieldstr);
97  g_free(var);
98 }
99 
100 
101 /* Initialize an evaluation context
102  */
103 TupleEvalContext * tuple_evalctx_new(void)
104 {
105  return g_new0(TupleEvalContext, 1);
106 }
107 
108 
109 /* "Reset" the evaluation context
110  */
111 void tuple_evalctx_reset(TupleEvalContext *ctx)
112 {
113  int i;
114 
115  for (i = 0; i < ctx->nvariables; i++)
116  if (ctx->variables[i]) {
117  ctx->variables[i]->fieldread = FALSE;
118  ctx->variables[i]->fieldvalid = FALSE;
119  str_unref (ctx->variables[i]->fieldstr);
120  ctx->variables[i]->fieldstr = NULL;
121  }
122 }
123 
124 
125 /* Free an evaluation context and associated data
126  */
127 void tuple_evalctx_free(TupleEvalContext *ctx)
128 {
129  int i;
130 
131  if (!ctx) return;
132 
133  /* Deallocate variables */
134  for (i = 0; i < ctx->nvariables; i++)
135  if (ctx->variables[i])
136  tuple_evalctx_free_var(ctx->variables[i]);
137 
138  g_free(ctx->variables);
139  g_free(ctx);
140 }
141 
142 
143 static int tuple_evalctx_add_var (TupleEvalContext * ctx, const char * name,
144  const int type, const TupleValueType ctype)
145 {
146  int i;
147  TupleEvalVar *tmp = g_new0(TupleEvalVar, 1);
148 
149  tmp->name = g_strdup(name);
150  tmp->type = type;
151  tmp->fieldidx = -1;
152  tmp->ctype = ctype;
153 
154  /* Find fieldidx, if any */
155  switch (type) {
156  case TUPLE_VAR_FIELD:
157  tmp->fieldidx = tuple_field_by_name (name);
158  tmp->ctype = tuple_field_get_type (tmp->fieldidx);
159  break;
160 
161  case TUPLE_VAR_CONST:
162  if (ctype == TUPLE_INT)
163  tmp->defvali = atoi(name);
164  break;
165  }
166 
167  /* Find a free slot */
168  for (i = 0; i < ctx->nvariables; i++)
169  if (!ctx->variables[i]) {
170  ctx->variables[i] = tmp;
171  return i;
172  }
173 
174  i = ctx->nvariables;
175  ctx->variables = g_renew(TupleEvalVar *, ctx->variables, ctx->nvariables + MIN_ALLOC_NODES);
176  memset(&(ctx->variables[ctx->nvariables]), 0, MIN_ALLOC_NODES * sizeof(TupleEvalVar *));
177  ctx->nvariables += MIN_ALLOC_NODES;
178  ctx->variables[i] = tmp;
179 
180  return i;
181 }
182 
183 
184 static void tuple_evalnode_insert(TupleEvalNode **nodes, TupleEvalNode *node)
185 {
186  if (*nodes) {
187  node->prev = (*nodes)->prev;
188  (*nodes)->prev->next = node;
189  (*nodes)->prev = node;
190  node->next = NULL;
191  } else {
192  *nodes = node;
193  node->prev = node;
194  node->next = NULL;
195  }
196 }
197 
198 
199 static TupleEvalNode *tuple_evalnode_new(void)
200 {
201  return g_new0(TupleEvalNode, 1);
202 }
203 
204 
205 void tuple_evalnode_free(TupleEvalNode *expr)
206 {
207  TupleEvalNode *curr = expr, *next;
208 
209  while (curr) {
210  next = curr->next;
211 
212  g_free(curr->text);
213 
214  if (curr->children)
215  tuple_evalnode_free(curr->children);
216 
217  g_free(curr);
218 
219  curr = next;
220  }
221 }
222 
223 
224 static TupleEvalNode *tuple_compiler_pass1(int *level, TupleEvalContext *ctx, char **expression);
225 
226 
227 static bool_t tc_get_item(TupleEvalContext *ctx,
228  char **str, char *buf, gssize max,
229  char endch, bool_t *literal, char *errstr, char *item)
230 {
231  gssize i = 0;
232  char *s = *str, tmpendch;
233 
234  if (*s == '"') {
235  if (*literal == FALSE) {
236  tuple_error(ctx, "Literal string value not allowed in '%s'.\n", item);
237  return FALSE;
238  }
239  s++;
240  *literal = TRUE;
241  tmpendch = '"';
242  } else {
243  *literal = FALSE;
244  tmpendch = endch;
245  }
246 
247  if (*literal == FALSE) {
248  while (*s != '\0' && *s != tmpendch && (isalnum(*s) || *s == '-') && i < (max - 1)) {
249  buf[i++] = *(s++);
250  }
251 
252  if (*s != tmpendch && *s != '}' && !isalnum(*s) && *s != '-') {
253  tuple_error(ctx, "Invalid field '%s' in '%s'.\n", *str, item);
254  return FALSE;
255  } else if (*s != tmpendch) {
256  tuple_error(ctx, "Expected '%c' in '%s'.\n", tmpendch, item);
257  return FALSE;
258  }
259  } else {
260  while (*s != '\0' && *s != tmpendch && i < (max - 1)) {
261  if (*s == '\\') s++;
262  buf[i++] = *(s++);
263  }
264  }
265  buf[i] = '\0';
266 
267  if (*literal) {
268  if (*s == tmpendch)
269  s++;
270  else {
271  tuple_error(ctx, "Expected literal string end ('%c') in '%s'.\n", tmpendch, item);
272  return FALSE;
273  }
274  }
275 
276  if (*s != endch) {
277  tuple_error(ctx, "Expected '%c' after %s in '%s'\n", endch, errstr, item);
278  return FALSE;
279  } else {
280  *str = s;
281  return TRUE;
282  }
283 }
284 
285 
286 static int tc_get_variable(TupleEvalContext *ctx, char *name, int type)
287 {
288  int i;
290 
291  if (name == '\0') return -1;
292 
293  if (isdigit(name[0])) {
294  ctype = TUPLE_INT;
295  type = TUPLE_VAR_CONST;
296  } else
297  ctype = TUPLE_STRING;
298 
299  if (type != TUPLE_VAR_CONST) {
300  for (i = 0; i < ctx->nvariables; i++)
301  if (ctx->variables[i] && !strcmp(ctx->variables[i]->name, name))
302  return i;
303  }
304 
305  return tuple_evalctx_add_var(ctx, name, type, ctype);
306 }
307 
308 
309 static bool_t tc_parse_construct(TupleEvalContext *ctx, TupleEvalNode **res, char *item, char **c, int *level, int opcode)
310 {
311  char tmps1[MAX_STR], tmps2[MAX_STR];
312  bool_t literal1 = TRUE, literal2 = TRUE;
313 
314  (*c)++;
315  if (tc_get_item(ctx, c, tmps1, MAX_STR, ',', &literal1, "tag1", item)) {
316  (*c)++;
317  if (tc_get_item(ctx, c, tmps2, MAX_STR, ':', &literal2, "tag2", item)) {
318  TupleEvalNode *tmp = tuple_evalnode_new();
319  (*c)++;
320 
321  tmp->opcode = opcode;
322  if ((tmp->var[0] = tc_get_variable(ctx, tmps1, literal1 ? TUPLE_VAR_CONST : TUPLE_VAR_FIELD)) < 0) {
323  tuple_evalnode_free(tmp);
324  tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, item);
325  return FALSE;
326  }
327  if ((tmp->var[1] = tc_get_variable(ctx, tmps2, literal2 ? TUPLE_VAR_CONST : TUPLE_VAR_FIELD)) < 0) {
328  tuple_evalnode_free(tmp);
329  tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps2, item);
330  return FALSE;
331  }
332  tmp->children = tuple_compiler_pass1(level, ctx, c);
333  tuple_evalnode_insert(res, tmp);
334  } else
335  return FALSE;
336  } else
337  return FALSE;
338 
339  return TRUE;
340 }
341 
342 
343 /* Compile format expression into TupleEvalNode tree.
344  * A "simple" straight compilation is sufficient in first pass, later
345  * passes can perform subexpression removal and other optimizations.
346  */
347 static TupleEvalNode *tuple_compiler_pass1(int *level, TupleEvalContext *ctx, char **expression)
348 {
349  TupleEvalNode *res = NULL, *tmp = NULL;
350  char *c = *expression, *item, tmps1[MAX_STR];
351  bool_t literal, end = FALSE;
352 
353  (*level)++;
354 
355  while (*c != '\0' && !end) {
356  tmp = NULL;
357  if (*c == '}') {
358  c++;
359  (*level)--;
360  end = TRUE;
361  } else if (*c == '$') {
362  /* Expression? */
363  item = c++;
364  if (*c == '{') {
365  int opcode;
366  char *expr = ++c;
367 
368  switch (*c) {
369  case '?': c++;
370  /* Exists? */
371  literal = FALSE;
372  if (tc_get_item(ctx, &c, tmps1, MAX_STR, ':', &literal, "tag", item)) {
373  c++;
374  tmp = tuple_evalnode_new();
375  tmp->opcode = OP_EXISTS;
376  if ((tmp->var[0] = tc_get_variable(ctx, tmps1, TUPLE_VAR_FIELD)) < 0) {
377  tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, expr);
378  goto ret_error;
379  }
380  tmp->children = tuple_compiler_pass1(level, ctx, &c);
381  tuple_evalnode_insert(&res, tmp);
382  } else
383  goto ret_error;
384  break;
385 
386  case '=': c++;
387  if (*c != '=') {
388  /* Definition */
389  literal = FALSE;
390  if (tc_get_item(ctx, &c, tmps1, MAX_STR, ',', &literal, "variable", item)) {
391  c++;
392  if (*c == '"') {
393  /* String */
394  c++;
395  } else if (isdigit(*c)) {
396  /* Integer */
397  }
398 
399  tuple_error(ctx, "Definitions are not yet supported!\n");
400  goto ret_error;
401  } else
402  goto ret_error;
403  } else {
404  /* Equals? */
405  if (!tc_parse_construct(ctx, &res, item, &c, level, OP_EQUALS))
406  goto ret_error;
407  }
408  break;
409 
410  case '!': c++;
411  if (*c != '=') goto ext_expression;
412  if (!tc_parse_construct(ctx, &res, item, &c, level, OP_NOT_EQUALS))
413  goto ret_error;
414  break;
415 
416  case '<': c++;
417  if (*c == '=') {
418  opcode = OP_LTEQ;
419  c++;
420  } else
421  opcode = OP_LT;
422 
423  if (!tc_parse_construct(ctx, &res, item, &c, level, opcode))
424  goto ret_error;
425  break;
426 
427  case '>': c++;
428  if (*c == '=') {
429  opcode = OP_GTEQ;
430  c++;
431  } else
432  opcode = OP_GT;
433 
434  if (!tc_parse_construct(ctx, &res, item, &c, level, opcode))
435  goto ret_error;
436  break;
437 
438  case '(': c++;
439  if (!strncmp(c, "empty)?", 7)) {
440  c += 7;
441  literal = FALSE;
442  if (tc_get_item(ctx, &c, tmps1, MAX_STR, ':', &literal, "tag", item)) {
443  c++;
444  tmp = tuple_evalnode_new();
445  tmp->opcode = OP_IS_EMPTY;
446  if ((tmp->var[0] = tc_get_variable(ctx, tmps1, TUPLE_VAR_FIELD)) < 0) {
447  tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, expr);
448  goto ret_error;
449  }
450  tmp->children = tuple_compiler_pass1(level, ctx, &c);
451  tuple_evalnode_insert(&res, tmp);
452  } else
453  goto ret_error;
454  } else
455  goto ext_expression;
456  break;
457 
458  default:
459  ext_expression:
460  /* Get expression content */
461  c = expr;
462  literal = FALSE;
463  if (tc_get_item(ctx, &c, tmps1, MAX_STR, '}', &literal, "field", item)) {
464  /* FIXME!! FIX ME! Check for external expressions */
465 
466  /* I HAS A FIELD - A field. You has it. */
467  tmp = tuple_evalnode_new();
468  tmp->opcode = OP_FIELD;
469  if ((tmp->var[0] = tc_get_variable(ctx, tmps1, TUPLE_VAR_FIELD)) < 0) {
470  tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, expr);
471  goto ret_error;
472  }
473  tuple_evalnode_insert(&res, tmp);
474  c++;
475 
476  } else
477  goto ret_error;
478  }
479  } else {
480  tuple_error(ctx, "Expected '{', got '%c' in '%s'.\n", *c, c);
481  goto ret_error;
482  }
483 
484  } else if (*c == '%') {
485  /* Function? */
486  item = c++;
487  if (*c == '{') {
488  gssize i = 0;
489  c++;
490 
491  while (*c != '\0' && (isalnum(*c) || *c == '-') && *c != '}' && *c != ':' && i < (MAX_STR - 1))
492  tmps1[i++] = *(c++);
493  tmps1[i] = '\0';
494 
495  if (*c == ':') {
496  c++;
497  } else if (*c == '}') {
498  c++;
499  } else if (*c == '\0') {
500  tuple_error(ctx, "Expected '}' or function arguments in '%s'\n", item);
501  goto ret_error;
502  }
503  } else {
504  tuple_error(ctx, "Expected '{', got '%c' in '%s'.\n", *c, c);
505  goto ret_error;
506  }
507  } else {
508  /* Parse raw/literal text */
509  gssize i = 0;
510  while (*c != '\0' && *c != '$' && *c != '%' && *c != '}' && i < (MAX_STR - 1)) {
511  if (*c == '\\') c++;
512  tmps1[i++] = *(c++);
513  }
514  tmps1[i] = '\0';
515 
516  tmp = tuple_evalnode_new();
517  tmp->opcode = OP_RAW;
518  tmp->text = g_strdup(tmps1);
519  tuple_evalnode_insert(&res, tmp);
520  }
521  }
522 
523  if (*level <= 0) {
524  tuple_error(ctx, "Syntax error! Uneven/unmatched nesting of elements in '%s'!\n", c);
525  goto ret_error;
526  }
527 
528  *expression = c;
529  return res;
530 
531 ret_error:
532  tuple_evalnode_free(tmp);
533  tuple_evalnode_free(res);
534  return NULL;
535 }
536 
537 
538 TupleEvalNode *tuple_formatter_compile(TupleEvalContext *ctx, char *expr)
539 {
540  int level = 0;
541  char *tmpexpr = expr;
542  TupleEvalNode *res1;
543 
544  res1 = tuple_compiler_pass1(&level, ctx, &tmpexpr);
545 
546  if (level != 1) {
547  tuple_error(ctx, "Syntax error! Uneven/unmatched nesting of elements! (%d)\n", level);
548  tuple_evalnode_free(res1);
549  return NULL;
550  }
551 
552  return res1;
553 }
554 
555 
556 /* Fetch a tuple field value. Return TRUE if found. */
557 static bool_t tf_get_fieldval (TupleEvalVar * var, const Tuple * tuple)
558 {
559  if (var->type != TUPLE_VAR_FIELD || var->fieldidx < 0)
560  return FALSE;
561 
562  if (var->fieldread)
563  return var->fieldvalid;
564 
565  if (tuple_get_value_type (tuple, var->fieldidx, NULL) != var->ctype) {
566  var->fieldread = TRUE;
567  var->fieldvalid = FALSE;
568  return FALSE;
569  }
570 
571  if (var->ctype == TUPLE_INT)
572  var->defvali = tuple_get_int (tuple, var->fieldidx, NULL);
573  else if (var->ctype == TUPLE_STRING)
574  var->fieldstr = tuple_get_str (tuple, var->fieldidx, NULL);
575 
576  var->fieldread = TRUE;
577  var->fieldvalid = TRUE;
578  return TRUE;
579 }
580 
581 
582 /* Fetch string or int value of given variable, whatever type it might be.
583  * Return VAR_* type for the variable.
584  */
585 static TupleValueType tf_get_var (char * * tmps, int * tmpi, TupleEvalVar *
586  var, const Tuple * tuple)
587 {
589  *tmps = NULL;
590  *tmpi = 0;
591 
592  switch (var->type) {
593  case TUPLE_VAR_CONST:
594  switch (var->ctype) {
595  case TUPLE_STRING: *tmps = var->name; break;
596  case TUPLE_INT: *tmpi = var->defvali; break;
597  default: /* Cannot happen */ break;
598  }
599  type = var->ctype;
600  break;
601 
602  case TUPLE_VAR_FIELD:
603  if (tf_get_fieldval (var, tuple)) {
604  type = var->ctype;
605  if (type == TUPLE_INT)
606  * tmpi = var->defvali;
607  else if (type == TUPLE_STRING)
608  * tmps = var->fieldstr;
609  }
610  break;
611  }
612 
613  return type;
614 }
615 
616 
617 /* Evaluate tuple in given TupleEval expression in given
618  * context and return resulting string.
619  */
620 static bool_t tuple_formatter_eval_do (TupleEvalContext * ctx, TupleEvalNode *
621  expr, const Tuple * tuple, GString * out)
622 {
623  TupleEvalNode *curr = expr;
624  TupleEvalVar *var0, *var1;
625  TupleValueType type0, type1;
626  int tmpi0, tmpi1;
627  char tmps[MAX_STR], *tmps0, *tmps1, *tmps2;
628  bool_t result;
629  int resulti;
630 
631  if (!expr) return FALSE;
632 
633  while (curr) {
634  const char *str = NULL;
635 
636  switch (curr->opcode) {
637  case OP_RAW:
638  str = curr->text;
639  break;
640 
641  case OP_FIELD:
642  var0 = ctx->variables[curr->var[0]];
643 
644  switch (var0->type) {
645  case TUPLE_VAR_FIELD:
646  if (tf_get_fieldval (var0, tuple)) {
647  switch (var0->ctype) {
648  case TUPLE_STRING:
649  str = var0->fieldstr;
650  break;
651 
652  case TUPLE_INT:
653  g_snprintf (tmps, sizeof (tmps), "%d", var0->defvali);
654  str = tmps;
655  break;
656 
657  default:
658  str = NULL;
659  }
660  }
661  break;
662  }
663  break;
664 
665  case OP_EQUALS:
666  case OP_NOT_EQUALS:
667  case OP_LT: case OP_LTEQ:
668  case OP_GT: case OP_GTEQ:
669  var0 = ctx->variables[curr->var[0]];
670  var1 = ctx->variables[curr->var[1]];
671 
672  type0 = tf_get_var(&tmps0, &tmpi0, var0, tuple);
673  type1 = tf_get_var(&tmps1, &tmpi1, var1, tuple);
674  result = FALSE;
675 
676  if (type0 != TUPLE_UNKNOWN && type1 != TUPLE_UNKNOWN) {
677  if (type0 == type1) {
678  if (type0 == TUPLE_STRING)
679  resulti = strcmp(tmps0, tmps1);
680  else
681  resulti = tmpi0 - tmpi1;
682  } else {
683  if (type0 == TUPLE_INT)
684  resulti = tmpi0 - atoi(tmps1);
685  else
686  resulti = atoi(tmps0) - tmpi1;
687  }
688 
689  switch (curr->opcode) {
690  case OP_EQUALS: result = (resulti == 0); break;
691  case OP_NOT_EQUALS: result = (resulti != 0); break;
692  case OP_LT: result = (resulti < 0); break;
693  case OP_LTEQ: result = (resulti <= 0); break;
694  case OP_GT: result = (resulti > 0); break;
695  case OP_GTEQ: result = (resulti >= 0); break;
696  default: result = FALSE;
697  }
698  }
699 
700  if (result && ! tuple_formatter_eval_do (ctx, curr->children, tuple, out))
701  return FALSE;
702  break;
703 
704  case OP_EXISTS:
705  if (tf_get_fieldval (ctx->variables[curr->var[0]], tuple)) {
706  if (! tuple_formatter_eval_do (ctx, curr->children, tuple, out))
707  return FALSE;
708  }
709  break;
710 
711  case OP_IS_EMPTY:
712  var0 = ctx->variables[curr->var[0]];
713 
714  if (tf_get_fieldval (var0, tuple)) {
715  switch (var0->ctype) {
716  case TUPLE_INT:
717  result = (var0->defvali == 0);
718  break;
719 
720  case TUPLE_STRING:
721  result = TRUE;
722  tmps2 = var0->fieldstr;
723 
724  while (result && tmps2 && *tmps2 != '\0') {
725  gunichar uc = g_utf8_get_char(tmps2);
726  if (g_unichar_isspace(uc))
727  tmps2 = g_utf8_next_char(tmps2);
728  else
729  result = FALSE;
730  }
731  break;
732 
733  default:
734  result = TRUE;
735  }
736  } else
737  result = TRUE;
738 
739  if (result && ! tuple_formatter_eval_do (ctx, curr->children, tuple, out))
740  return FALSE;
741  break;
742 
743  default:
744  tuple_error(ctx, "Unimplemented opcode %d!\n", curr->opcode);
745  return FALSE;
746  break;
747  }
748 
749  if (str)
750  g_string_append (out, str);
751 
752  curr = curr->next;
753  }
754 
755  return TRUE;
756 }
757 
758 void tuple_formatter_eval (TupleEvalContext * ctx, TupleEvalNode * expr,
759  const Tuple * tuple, GString * out)
760 {
761  g_string_truncate (out, 0);
762  tuple_formatter_eval_do (ctx, expr, tuple, out);
763 }
struct _TupleEvalNode * prev
struct _TupleEvalNode * next
struct _TupleEvalNode * children
static bool_t tc_parse_construct(TupleEvalContext *ctx, TupleEvalNode **res, char *item, char **c, int *level, int opcode)
static TupleValueType tf_get_var(char **tmps, int *tmpi, TupleEvalVar *var, const Tuple *tuple)
#define MAX_STR
static int tc_get_variable(TupleEvalContext *ctx, char *name, int type)
static void tuple_evalnode_insert(TupleEvalNode **nodes, TupleEvalNode *node)
static bool_t tf_get_fieldval(TupleEvalVar *var, const Tuple *tuple)
type
Definition: plugins-api.h:41
bool_t fieldread
#define FALSE
Definition: core.h:37
EXPORT int tuple_field_by_name(const char *name)
Definition: tuple.c:165
Index Index bool_t
Definition: playlist-api.h:122
static TupleEvalNode * tuple_compiler_pass1(int *level, TupleEvalContext *ctx, char **expression)
TupleValueType
Definition: tuple.h:82
const char * name
Definition: plugin-init.c:38
#define NULL
Definition: core.h:29
void tuple_evalctx_reset(TupleEvalContext *ctx)
EXPORT TupleValueType tuple_field_get_type(int field)
Definition: tuple.c:186
#define TRUE
Definition: core.h:39
void tuple_evalnode_free(TupleEvalNode *expr)
void str_unref(char *str)
Definition: strpool.c:131
static TupleEvalNode * tuple_evalnode_new(void)
TupleEvalContext * tuple_evalctx_new(void)
#define tuple_error(ctx,...)
void tuple_formatter_eval(TupleEvalContext *ctx, TupleEvalNode *expr, const Tuple *tuple, GString *out)
EXPORT char * tuple_get_str(const Tuple *tuple, int nfield, const char *field)
Definition: tuple.c:478
static int tuple_evalctx_add_var(TupleEvalContext *ctx, const char *name, const int type, const TupleValueType ctype)
#define TUPLEZ_MAX_VARS
EXPORT TupleValueType tuple_get_value_type(const Tuple *tuple, int nfield, const char *field)
Returns TupleValueType of given #Tuple field.
Definition: tuple.c:459
static bool_t tuple_formatter_eval_do(TupleEvalContext *ctx, TupleEvalNode *expr, const Tuple *tuple, GString *out)
TupleEvalNode * tuple_formatter_compile(TupleEvalContext *ctx, char *expr)
TupleValueType ctype
TupleEvalVar ** variables
bool_t fieldvalid
void tuple_evalctx_free(TupleEvalContext *ctx)
static void tuple_evalctx_free_var(TupleEvalVar *var)
struct @17::@18::@20 s
#define MIN_ALLOC_NODES
static bool_t tc_get_item(TupleEvalContext *ctx, char **str, char *buf, gssize max, char endch, bool_t *literal, char *errstr, char *item)
int var[TUPLEZ_MAX_VARS]
EXPORT int tuple_get_int(const Tuple *tuple, int nfield, const char *field)
Returns integer associated to #Tuple field.
Definition: tuple.c:509