changeset 3821:09de487ea683

Branch merge.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 20 Oct 2007 06:08:25 +0300
parents 6b5a1d1d001e (current diff) 94927e11786e (diff)
children c597262d6d50
files
diffstat 2 files changed, 56 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/tuple_compiler.c	Sat Oct 20 06:07:49 2007 +0300
+++ b/src/audacious/tuple_compiler.c	Sat Oct 20 06:08:25 2007 +0300
@@ -23,7 +23,6 @@
  * - implement definitions (${=foo,"baz"} ${=foo,1234})
  * - implement functions
  * - implement handling of external expressions
- * - error handling issues?
  * - evaluation context: how local variables should REALLY work?
  *   currently there is just a single context, is a "global" context needed?
  */
@@ -38,14 +37,14 @@
 #define MIN_ALLOC_BUF	(64)
 
 
-void tuple_error(const char *fmt, ...)
+void tuple_error(TupleEvalContext *ctx, const gchar *fmt, ...)
 {
   va_list ap;
-  fprintf(stderr, "compiler: ");
+  g_free(ctx->errmsg);
   va_start(ap, fmt);
-  vfprintf(stderr, fmt, ap);
+  ctx->errmsg = g_strdup_vprintf(fmt, ap);
   va_end(ap);
-//  exit(5);
+  ctx->iserror = TRUE;
 }
 
 
@@ -89,6 +88,8 @@
       if (ctx->variables[i]->istemp)
         tuple_evalctx_free_var(ctx->variables[i]);
     }
+  
+  ctx->iserror = FALSE;
 }
 
 
@@ -122,7 +123,8 @@
 gint tuple_evalctx_add_var(TupleEvalContext *ctx, const gchar *name, const gboolean istemp, const gint type)
 {
   gint i, ref = -1;
-  TupleEvalVar * tmp = g_new0(TupleEvalVar, 1);
+  TupleEvalVar *tmp = g_new0(TupleEvalVar, 1);
+  assert(tmp != NULL);
 
   tmp->name = g_strdup(name);
   tmp->istemp = istemp;
@@ -209,16 +211,18 @@
 static TupleEvalNode *tuple_compiler_pass1(gint *level, TupleEvalContext *ctx, gchar **expression);
 
 
-static gboolean tc_get_item(gchar **str, gchar *buf, size_t max, gchar endch, gboolean *literal, gchar *errstr, gchar *item)
+static gboolean tc_get_item(TupleEvalContext *ctx,
+    gchar **str, gchar *buf, gssize max,
+    gchar endch, gboolean *literal, gchar *errstr, gchar *item)
 {
-  size_t i = 0;
+  gssize i = 0;
   gchar *s = *str, tmpendch;
   assert(str != NULL);
   assert(buf != NULL);
   
   if (*s == '"') {
     if (*literal == FALSE) {
-      tuple_error("Literal string value not allowed in '%s'.\n", item);
+      tuple_error(ctx, "Literal string value not allowed in '%s'.\n", item);
       return FALSE;
     }
     s++;
@@ -235,10 +239,10 @@
     }
     
     if (*s != tmpendch && *s != '}' && !isalnum(*s) && *s != '-') {
-      tuple_error("Invalid field '%s' in '%s'.\n", *str, item);
+      tuple_error(ctx, "Invalid field '%s' in '%s'.\n", *str, item);
       return FALSE;
     } else if (*s != tmpendch) {
-      tuple_error("Expected '%c' in '%s'.\n", tmpendch, item);
+      tuple_error(ctx, "Expected '%c' in '%s'.\n", tmpendch, item);
       return FALSE;
     }
   } else {
@@ -253,13 +257,13 @@
     if (*s == tmpendch)
       s++;
     else {
-      tuple_error("Expected literal string end ('%c') in '%s'.\n", tmpendch, item);
+      tuple_error(ctx, "Expected literal string end ('%c') in '%s'.\n", tmpendch, item);
       return FALSE;
     }
   }
 
   if (*s != endch) {
-    tuple_error("Expected '%c' after %s in '%s'\n", endch, errstr, item);
+    tuple_error(ctx, "Expected '%c' after %s in '%s'\n", endch, errstr, item);
     return FALSE;
   } else {
     *str = s;
@@ -288,21 +292,21 @@
   gboolean literal1 = TRUE, literal2 = TRUE;
 
   (*c)++;
-  if (tc_get_item(c, tmps1, MAX_STR, ',', &literal1, "tag1", item)) {
+  if (tc_get_item(ctx, c, tmps1, MAX_STR, ',', &literal1, "tag1", item)) {
     (*c)++;
-    if (tc_get_item(c, tmps2, MAX_STR, ':', &literal2, "tag2", item)) {
+    if (tc_get_item(ctx, c, tmps2, MAX_STR, ':', &literal2, "tag2", item)) {
       TupleEvalNode *tmp = tuple_evalnode_new();
       (*c)++;
 
       tmp->opcode = opcode;
       if ((tmp->var[0] = tc_get_variable(ctx, tmps1, literal1 ? VAR_CONST : VAR_FIELD)) < 0) {
         tuple_evalnode_free(tmp);
-        tuple_error("Invalid variable '%s' in '%s'.\n", tmps1, item);
+        tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, item);
         return FALSE;
       }
       if ((tmp->var[1] = tc_get_variable(ctx, tmps2, literal2 ? VAR_CONST : VAR_FIELD)) < 0) {
         tuple_evalnode_free(tmp);
-        tuple_error("Invalid variable '%s' in '%s'.\n", tmps2, item);
+        tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps2, item);
         return FALSE;
       }
       tmp->children = tuple_compiler_pass1(level, ctx, c);
@@ -347,12 +351,12 @@
           case '?': c++;
             /* Exists? */
             literal = FALSE;
-            if (tc_get_item(&c, tmps1, MAX_STR, ':', &literal, "tag", item)) {
+            if (tc_get_item(ctx, &c, tmps1, MAX_STR, ':', &literal, "tag", item)) {
               c++;
               tmp = tuple_evalnode_new();
               tmp->opcode = OP_EXISTS;
               if ((tmp->var[0] = tc_get_variable(ctx, tmps1, VAR_FIELD)) < 0) {
-                tuple_error("Invalid variable '%s' in '%s'.\n", tmps1, expr);
+                tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, expr);
                 goto ret_error;
               }
               tmp->children = tuple_compiler_pass1(level, ctx, &c);
@@ -365,7 +369,7 @@
             if (*c != '=') {
               /* Definition */
               literal = FALSE;
-              if (tc_get_item(&c, tmps1, MAX_STR, ',', &literal, "variable", item)) {
+              if (tc_get_item(ctx, &c, tmps1, MAX_STR, ',', &literal, "variable", item)) {
                 c++;
                 if (*c == '"') {
                   /* String */
@@ -374,7 +378,7 @@
                   /* Integer */
                 }
                 
-                tuple_error("Definitions are not yet supported!\n");
+                tuple_error(ctx, "Definitions are not yet supported!\n");
                 goto ret_error;
               } else
                 goto ret_error;
@@ -417,12 +421,12 @@
             if (!strncmp(c, "empty)?", 7)) {
               c += 7;
               literal = FALSE;
-              if (tc_get_item(&c, tmps1, MAX_STR, ':', &literal, "tag", item)) {
+              if (tc_get_item(ctx, &c, tmps1, MAX_STR, ':', &literal, "tag", item)) {
                 c++;
                 tmp = tuple_evalnode_new();
                 tmp->opcode = OP_EXISTS;
                 if ((tmp->var[0] = tc_get_variable(ctx, tmps1, VAR_FIELD)) < 0) {
-                  tuple_error("Invalid variable '%s' in '%s'.\n", tmps1, expr);
+                  tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, expr);
                   goto ret_error;
                 }
                 tmp->children = tuple_compiler_pass1(level, ctx, &c);
@@ -438,14 +442,14 @@
             /* Get expression content */
             c = expr;
             literal = FALSE;
-            if (tc_get_item(&c, tmps1, MAX_STR, '}', &literal, "field", item)) {
+            if (tc_get_item(ctx, &c, tmps1, MAX_STR, '}', &literal, "field", item)) {
               /* FIXME!! FIX ME! Check for external expressions */
               
               /* I HAS A FIELD - A field. You has it. */
               tmp = tuple_evalnode_new();
               tmp->opcode = OP_FIELD;
               if ((tmp->var[0] = tc_get_variable(ctx, tmps1, VAR_FIELD)) < 0) {
-                tuple_error("Invalid variable '%s' in '%s'.\n", tmps1, expr);
+                tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, expr);
                 goto ret_error;
               }
               tuple_evalnode_insert(&res, tmp);
@@ -455,7 +459,7 @@
               goto ret_error;
         }        
       } else {
-        tuple_error("Expected '{', got '%c' in '%s'.\n", *c, c);
+        tuple_error(ctx, "Expected '{', got '%c' in '%s'.\n", *c, c);
         goto ret_error;
       }
        
@@ -463,7 +467,7 @@
       /* Function? */
       item = c++;
       if (*c == '{') {
-        size_t i = 0;
+        gssize i = 0;
         c++;
         
         while (*c != '\0' && (isalnum(*c) || *c == '-') && *c != '}' && *c != ':' && i < (MAX_STR - 1))
@@ -475,16 +479,16 @@
         } else if (*c == '}') {
           c++;
         } else if (*c == '\0') {
-          tuple_error("Expected '}' or function arguments in '%s'\n", item);
+          tuple_error(ctx, "Expected '}' or function arguments in '%s'\n", item);
           goto ret_error;
         }
       } else {
-        tuple_error("Expected '{', got '%c' in '%s'.\n", *c, c);
+        tuple_error(ctx, "Expected '{', got '%c' in '%s'.\n", *c, c);
         goto ret_error;
       }
     } else {
       /* Parse raw/literal text */
-      size_t i = 0;
+      gssize i = 0;
       while (*c != '\0' && *c != '$' && *c != '%' && *c != '}' && i < (MAX_STR - 1)) {
         if (*c == '\\') c++;
         tmps1[i++] = *(c++);
@@ -499,7 +503,7 @@
   }
 
   if (*level <= 0) {
-    tuple_error("Syntax error! Uneven/unmatched nesting of elements in '%s'!\n", c);
+    tuple_error(ctx, "Syntax error! Uneven/unmatched nesting of elements in '%s'!\n", c);
     goto ret_error;
   }
   
@@ -518,7 +522,6 @@
   /* TupleEvalNode *curr = expr; */
   TupleEvalNode *res = NULL;
   assert(ctx != NULL);
-  assert(expr != NULL);
   
   return res;
 }
@@ -534,7 +537,7 @@
   res1 = tuple_compiler_pass1(&level, ctx, &tmpexpr);
 
   if (level != 1) {
-    tuple_error("Syntax error! Uneven/unmatched nesting of elements! (%d)\n", level);
+    tuple_error(ctx, "Syntax error! Uneven/unmatched nesting of elements! (%d)\n", level);
     tuple_evalnode_free(res1);
     return NULL;
   }
@@ -598,16 +601,15 @@
 /* Evaluate tuple in given TupleEval expression in given
  * context and return resulting string.
  */
-static gboolean tuple_formatter_eval_do(TupleEvalContext *ctx, TupleEvalNode *expr, Tuple *tuple, gchar **res, size_t *resmax, size_t *reslen)
+static gboolean tuple_formatter_eval_do(TupleEvalContext *ctx, TupleEvalNode *expr, Tuple *tuple, gchar **res, gssize *resmax, gssize *reslen)
 {
   TupleEvalNode *curr = expr;
-  gchar tmps[MAX_STR], *tmps2;
+  TupleEvalVar *var0, *var1;
+  TupleValueType type0, type1;
+  gint tmpi0, tmpi1;
+  gchar tmps[MAX_STR], *tmps0, *tmps1, *tmps2;
   gboolean result;
   gint resulti;
-  TupleEvalVar *var0, *var1;
-  gint tmpi0, tmpi1;
-  gchar *tmps0, *tmps1;
-  TupleValueType type0, type1;
   
   if (!expr) return FALSE;
   
@@ -635,7 +637,7 @@
                   break;
           
                 case TUPLE_INT:
-                  snprintf(tmps, sizeof(tmps), "%d", var0->fieldref->value.integer);
+                  g_snprintf(tmps, sizeof(tmps), "%d", var0->fieldref->value.integer);
                   str = tmps;
                   break;
                 
@@ -669,7 +671,7 @@
             resulti = strcmp(tmps0, tmps1);
           else
             resulti = tmpi0 - tmpi1;
-
+          
           switch (curr->opcode) {
             case OP_EQUALS:     result = (resulti == 0); break;
             case OP_NOT_EQUALS: result = (resulti != 0); break;
@@ -679,7 +681,7 @@
             case OP_GTEQ:       result = (resulti >= 0); break;
             default:		result = FALSE;
           }
-            
+          
           if (result && !tuple_formatter_eval_do(ctx, curr->children, tuple, res, resmax, reslen))
             return FALSE;
         } else {
@@ -700,15 +702,16 @@
           case TUPLE_STRING:
             result = TRUE;
             tmps2 = var0->fieldref->value.string;
-          
+            
             while (result && *tmps2 != '\0') {
-              if (*tmps2 == ' ')
-                tmps2++;
+              gunichar uc = g_utf8_get_char(tmps2);
+              if (g_unichar_isspace(uc))
+                g_utf8_next_char(tmps2);
               else
                 result = FALSE;
             }
             break;
-
+            
           default:
             result = TRUE;
           }
@@ -720,7 +723,7 @@
         break;
       
       default:
-        tuple_error("Unimplemented opcode %d!\n", curr->opcode);
+        tuple_error(ctx, "Unimplemented opcode %d!\n", curr->opcode);
         return FALSE;
         break;
     }
@@ -730,7 +733,7 @@
       *reslen += strlen(str);
       if (*res) {
         if (*reslen >= *resmax) {
-          *resmax += MIN_ALLOC_BUF;
+          *resmax += *reslen + MIN_ALLOC_BUF;
           *res = g_realloc(*res, *resmax);
         }
         
@@ -753,7 +756,7 @@
 gchar *tuple_formatter_eval(TupleEvalContext *ctx, TupleEvalNode *expr, Tuple *tuple)
 {
   gchar *res = g_strdup("");
-  size_t resmax = 0, reslen = 0;
+  gssize resmax = 0, reslen = 0;
   assert(ctx != NULL);
   assert(tuple != NULL);
   
--- a/src/audacious/tuple_compiler.h	Sat Oct 20 06:07:49 2007 +0300
+++ b/src/audacious/tuple_compiler.h	Sat Oct 20 06:08:25 2007 +0300
@@ -88,6 +88,10 @@
     gint nvariables, nfunctions, nexpressions;
     TupleEvalVar **variables;
     TupleEvalFunc **functions;
+    
+    /* Error context */
+    gboolean iserror;
+    gchar *errmsg;
 } TupleEvalContext;