| /* GStreamer |
| * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #include <string.h> |
| #include <stdlib.h> |
| |
| #include "asmrules.h" |
| |
| #define MAX_RULE_LENGTH 2048 |
| |
| /* define to enable some more debug */ |
| #undef DEBUG |
| |
| static GstASMNode * |
| gst_asm_node_new (void) |
| { |
| GstASMNode *node; |
| |
| node = g_new0 (GstASMNode, 1); |
| node->type = GST_ASM_NODE_UNKNOWN; |
| |
| return node; |
| } |
| |
| static void |
| gst_asm_node_free (GstASMNode * node) |
| { |
| if (node->left) |
| gst_asm_node_free (node->left); |
| if (node->right) |
| gst_asm_node_free (node->right); |
| if (node->type == GST_ASM_NODE_VARIABLE && node->data.varname) |
| g_free (node->data.varname); |
| g_free (node); |
| } |
| |
| static gfloat |
| gst_asm_operator_eval (GstASMOp optype, gfloat left, gfloat right) |
| { |
| gfloat result = 0.0; |
| |
| switch (optype) { |
| case GST_ASM_OP_GREATER: |
| result = (gfloat) (left > right); |
| break; |
| case GST_ASM_OP_LESS: |
| result = (gfloat) (left < right); |
| break; |
| case GST_ASM_OP_GREATEREQUAL: |
| result = (gfloat) (left >= right); |
| break; |
| case GST_ASM_OP_LESSEQUAL: |
| result = (gfloat) (left <= right); |
| break; |
| case GST_ASM_OP_EQUAL: |
| result = (gfloat) (left == right); |
| break; |
| case GST_ASM_OP_NOTEQUAL: |
| result = (gfloat) (left != right); |
| break; |
| case GST_ASM_OP_AND: |
| result = (gfloat) (left && right); |
| break; |
| case GST_ASM_OP_OR: |
| result = (gfloat) (left || right); |
| break; |
| default: |
| break; |
| } |
| return result; |
| } |
| |
| static gfloat |
| gst_asm_node_evaluate (GstASMNode * node, GHashTable * vars) |
| { |
| gfloat result = 0.0; |
| |
| if (node == NULL) |
| return 0.0; |
| |
| switch (node->type) { |
| case GST_ASM_NODE_VARIABLE: |
| { |
| gchar *val; |
| |
| val = g_hash_table_lookup (vars, node->data.varname); |
| if (val) |
| result = (gfloat) atof (val); |
| break; |
| } |
| case GST_ASM_NODE_INTEGER: |
| result = (gfloat) node->data.intval; |
| break; |
| case GST_ASM_NODE_FLOAT: |
| result = node->data.floatval; |
| break; |
| case GST_ASM_NODE_OPERATOR: |
| { |
| gfloat left, right; |
| |
| left = gst_asm_node_evaluate (node->left, vars); |
| right = gst_asm_node_evaluate (node->right, vars); |
| |
| result = gst_asm_operator_eval (node->data.optype, left, right); |
| break; |
| } |
| default: |
| break; |
| } |
| return result; |
| } |
| |
| #define IS_SPACE(p) (((p) == ' ') || ((p) == '\n') || \ |
| ((p) == '\r') || ((p) == '\t')) |
| #define IS_RULE_DELIM(p) (((p) == ',') || ((p) == ';') || ((p) == ')')) |
| #define IS_OPERATOR(p) (((p) == '>') || ((p) == '<') || \ |
| ((p) == '=') || ((p) == '!') || \ |
| ((p) == '&') || ((p) == '|')) |
| #define IS_NUMBER(p) ((((p) >= '0') && ((p) <= '9')) || ((p) == '.')) |
| #define IS_CHAR(p) (!IS_OPERATOR(ch) && !IS_RULE_DELIM(ch) && (ch != '\0')) |
| |
| #define IS_OP_TOKEN(t) (((t) == GST_ASM_TOKEN_AND) || ((t) == GST_ASM_TOKEN_OR)) |
| #define IS_COND_TOKEN(t) (((t) == GST_ASM_TOKEN_LESS) || ((t) == GST_ASM_TOKEN_LESSEQUAL) || \ |
| ((t) == GST_ASM_TOKEN_GREATER) || ((t) == GST_ASM_TOKEN_GREATEREQUAL) || \ |
| ((t) == GST_ASM_TOKEN_EQUAL) || ((t) == GST_ASM_TOKEN_NOTEQUAL)) |
| |
| typedef struct |
| { |
| const gchar *buffer; |
| gint pos; |
| gchar ch; |
| |
| GstASMToken token; |
| gchar val[MAX_RULE_LENGTH]; |
| } GstASMScan; |
| |
| #define NEXT_CHAR(scan) ((scan)->ch = (scan)->buffer[(scan)->pos++]) |
| #define THIS_CHAR(scan) ((scan)->ch) |
| |
| static GstASMScan * |
| gst_asm_scan_new (const gchar * buffer) |
| { |
| GstASMScan *scan; |
| |
| scan = g_new0 (GstASMScan, 1); |
| scan->buffer = buffer; |
| NEXT_CHAR (scan); |
| |
| return scan; |
| } |
| |
| static void |
| gst_asm_scan_free (GstASMScan * scan) |
| { |
| g_free (scan); |
| } |
| |
| static void |
| gst_asm_scan_string (GstASMScan * scan, gchar delim) |
| { |
| gchar ch; |
| gint i = 0; |
| |
| ch = THIS_CHAR (scan); |
| while ((ch != delim) && (ch != '\0')) { |
| if (i < MAX_RULE_LENGTH - 1) |
| scan->val[i++] = ch; |
| ch = NEXT_CHAR (scan); |
| if (ch == '\\') |
| ch = NEXT_CHAR (scan); |
| } |
| scan->val[i] = '\0'; |
| |
| if (ch == delim) |
| NEXT_CHAR (scan); |
| |
| scan->token = GST_ASM_TOKEN_STRING; |
| } |
| |
| static void |
| gst_asm_scan_number (GstASMScan * scan) |
| { |
| gchar ch; |
| gint i = 0; |
| gboolean have_float = FALSE; |
| |
| ch = THIS_CHAR (scan); |
| /* real strips all spaces that are not inside quotes for numbers */ |
| while ((IS_NUMBER (ch) || IS_SPACE (ch))) { |
| if (i < (MAX_RULE_LENGTH - 1) && !IS_SPACE (ch)) |
| scan->val[i++] = ch; |
| if (ch == '.') |
| have_float = TRUE; |
| ch = NEXT_CHAR (scan); |
| } |
| scan->val[i] = '\0'; |
| |
| if (have_float) |
| scan->token = GST_ASM_TOKEN_FLOAT; |
| else |
| scan->token = GST_ASM_TOKEN_INT; |
| } |
| |
| static void |
| gst_asm_scan_identifier (GstASMScan * scan) |
| { |
| gchar ch; |
| gint i = 0; |
| |
| ch = THIS_CHAR (scan); |
| /* real strips all spaces that are not inside quotes for identifiers */ |
| while ((IS_CHAR (ch) || IS_SPACE (ch))) { |
| if (i < (MAX_RULE_LENGTH - 1) && !IS_SPACE (ch)) |
| scan->val[i++] = ch; |
| ch = NEXT_CHAR (scan); |
| } |
| scan->val[i] = '\0'; |
| |
| scan->token = GST_ASM_TOKEN_IDENTIFIER; |
| } |
| |
| static void |
| gst_asm_scan_print_token (GstASMScan * scan) |
| { |
| #ifdef DEBUG |
| switch (scan->token) { |
| case GST_ASM_TOKEN_NONE: |
| g_print ("none\n"); |
| break; |
| case GST_ASM_TOKEN_EOF: |
| g_print ("EOF\n"); |
| break; |
| |
| case GST_ASM_TOKEN_INT: |
| g_print ("INT %d\n", atoi (scan->val)); |
| break; |
| case GST_ASM_TOKEN_FLOAT: |
| g_print ("FLOAT %f\n", atof (scan->val)); |
| break; |
| case GST_ASM_TOKEN_IDENTIFIER: |
| g_print ("ID %s\n", scan->val); |
| break; |
| case GST_ASM_TOKEN_STRING: |
| g_print ("STRING %s\n", scan->val); |
| break; |
| |
| case GST_ASM_TOKEN_HASH: |
| g_print ("HASH\n"); |
| break; |
| case GST_ASM_TOKEN_SEMICOLON: |
| g_print ("SEMICOLON\n"); |
| break; |
| case GST_ASM_TOKEN_COMMA: |
| g_print ("COMMA\n"); |
| break; |
| case GST_ASM_TOKEN_EQUAL: |
| g_print ("==\n"); |
| break; |
| case GST_ASM_TOKEN_NOTEQUAL: |
| g_print ("!=\n"); |
| break; |
| case GST_ASM_TOKEN_AND: |
| g_print ("&&\n"); |
| break; |
| case GST_ASM_TOKEN_OR: |
| g_print ("||\n"); |
| break; |
| case GST_ASM_TOKEN_LESS: |
| g_print ("<\n"); |
| break; |
| case GST_ASM_TOKEN_LESSEQUAL: |
| g_print ("<=\n"); |
| break; |
| case GST_ASM_TOKEN_GREATER: |
| g_print (">\n"); |
| break; |
| case GST_ASM_TOKEN_GREATEREQUAL: |
| g_print (">=\n"); |
| break; |
| case GST_ASM_TOKEN_DOLLAR: |
| g_print ("$\n"); |
| break; |
| case GST_ASM_TOKEN_LPAREN: |
| g_print ("(\n"); |
| break; |
| case GST_ASM_TOKEN_RPAREN: |
| g_print (")\n"); |
| break; |
| default: |
| break; |
| } |
| #endif |
| } |
| |
| static GstASMToken |
| gst_asm_scan_next_token (GstASMScan * scan) |
| { |
| gchar ch; |
| |
| ch = THIS_CHAR (scan); |
| |
| /* skip spaces */ |
| while (IS_SPACE (ch)) |
| ch = NEXT_CHAR (scan); |
| |
| /* remove \ which is common in front of " */ |
| while (ch == '\\') |
| ch = NEXT_CHAR (scan); |
| |
| switch (ch) { |
| case '#': |
| scan->token = GST_ASM_TOKEN_HASH; |
| NEXT_CHAR (scan); |
| break; |
| case ';': |
| scan->token = GST_ASM_TOKEN_SEMICOLON; |
| NEXT_CHAR (scan); |
| break; |
| case ',': |
| scan->token = GST_ASM_TOKEN_COMMA; |
| NEXT_CHAR (scan); |
| break; |
| case '=': |
| scan->token = GST_ASM_TOKEN_EQUAL; |
| if (NEXT_CHAR (scan) == '=') |
| NEXT_CHAR (scan); |
| break; |
| case '!': |
| if (NEXT_CHAR (scan) == '=') { |
| scan->token = GST_ASM_TOKEN_NOTEQUAL; |
| NEXT_CHAR (scan); |
| } |
| break; |
| case '&': |
| scan->token = GST_ASM_TOKEN_AND; |
| if (NEXT_CHAR (scan) == '&') |
| NEXT_CHAR (scan); |
| break; |
| case '|': |
| scan->token = GST_ASM_TOKEN_OR; |
| if (NEXT_CHAR (scan) == '|') |
| NEXT_CHAR (scan); |
| break; |
| case '<': |
| scan->token = GST_ASM_TOKEN_LESS; |
| if (NEXT_CHAR (scan) == '=') { |
| scan->token = GST_ASM_TOKEN_LESSEQUAL; |
| NEXT_CHAR (scan); |
| } |
| break; |
| case '>': |
| scan->token = GST_ASM_TOKEN_GREATER; |
| if (NEXT_CHAR (scan) == '=') { |
| scan->token = GST_ASM_TOKEN_GREATEREQUAL; |
| NEXT_CHAR (scan); |
| } |
| break; |
| case '$': |
| scan->token = GST_ASM_TOKEN_DOLLAR; |
| NEXT_CHAR (scan); |
| break; |
| case '(': |
| scan->token = GST_ASM_TOKEN_LPAREN; |
| NEXT_CHAR (scan); |
| break; |
| case ')': |
| scan->token = GST_ASM_TOKEN_RPAREN; |
| NEXT_CHAR (scan); |
| break; |
| case '"': |
| NEXT_CHAR (scan); |
| gst_asm_scan_string (scan, '"'); |
| break; |
| case '\'': |
| NEXT_CHAR (scan); |
| gst_asm_scan_string (scan, '\''); |
| break; |
| case '0': |
| case '1': |
| case '2': |
| case '3': |
| case '4': |
| case '5': |
| case '6': |
| case '7': |
| case '8': |
| case '9': |
| gst_asm_scan_number (scan); |
| break; |
| case '\0': |
| scan->token = GST_ASM_TOKEN_EOF; |
| break; |
| default: |
| gst_asm_scan_identifier (scan); |
| break; |
| } |
| gst_asm_scan_print_token (scan); |
| return scan->token; |
| } |
| |
| static GstASMRule * |
| gst_asm_rule_new (void) |
| { |
| GstASMRule *rule; |
| |
| rule = g_new (GstASMRule, 1); |
| rule->root = NULL; |
| rule->props = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); |
| |
| return rule; |
| } |
| |
| static void |
| gst_asm_rule_free (GstASMRule * rule) |
| { |
| g_hash_table_destroy (rule->props); |
| if (rule->root) |
| gst_asm_node_free (rule->root); |
| g_free (rule); |
| } |
| |
| static void |
| gst_asm_rule_add_property (GstASMRule * rule, gchar * key, gchar * val) |
| { |
| g_hash_table_insert (rule->props, key, val); |
| } |
| |
| static GstASMNode *gst_asm_scan_parse_condition (GstASMScan * scan); |
| |
| static GstASMNode * |
| gst_asm_scan_parse_operand (GstASMScan * scan) |
| { |
| GstASMNode *node; |
| |
| switch (scan->token) { |
| case GST_ASM_TOKEN_DOLLAR: |
| gst_asm_scan_next_token (scan); |
| |
| if (scan->token != GST_ASM_TOKEN_IDENTIFIER) |
| g_warning ("identifier expected"); |
| |
| node = gst_asm_node_new (); |
| node->type = GST_ASM_NODE_VARIABLE; |
| node->data.varname = g_strdup (scan->val); |
| break; |
| case GST_ASM_TOKEN_INT: |
| node = gst_asm_node_new (); |
| node->type = GST_ASM_NODE_INTEGER; |
| node->data.intval = (gfloat) atof (scan->val); |
| break; |
| case GST_ASM_TOKEN_FLOAT: |
| node = gst_asm_node_new (); |
| node->type = GST_ASM_NODE_FLOAT; |
| node->data.floatval = atoi (scan->val); |
| break; |
| case GST_ASM_TOKEN_LPAREN: |
| gst_asm_scan_next_token (scan); |
| node = gst_asm_scan_parse_condition (scan); |
| if (scan->token != GST_ASM_TOKEN_RPAREN) |
| g_warning (") expected"); |
| break; |
| default: |
| g_warning ("$ <number> or ) expected"); |
| node = NULL; |
| break; |
| } |
| gst_asm_scan_next_token (scan); |
| |
| return node; |
| } |
| |
| static GstASMNode * |
| gst_asm_scan_parse_expression (GstASMScan * scan) |
| { |
| GstASMNode *node, *left; |
| |
| node = gst_asm_scan_parse_operand (scan); |
| |
| while (IS_COND_TOKEN (scan->token)) { |
| left = node; |
| |
| node = gst_asm_node_new (); |
| node->type = GST_ASM_NODE_OPERATOR; |
| node->data.optype = (GstASMOp) scan->token; |
| |
| gst_asm_scan_next_token (scan); |
| |
| node->right = gst_asm_scan_parse_operand (scan); |
| node->left = left; |
| } |
| return node; |
| } |
| |
| static GstASMNode * |
| gst_asm_scan_parse_condition (GstASMScan * scan) |
| { |
| GstASMNode *node, *left; |
| |
| node = gst_asm_scan_parse_expression (scan); |
| |
| while (IS_OP_TOKEN (scan->token)) { |
| left = node; |
| |
| node = gst_asm_node_new (); |
| node->type = GST_ASM_NODE_OPERATOR; |
| node->data.optype = (GstASMOp) scan->token; |
| |
| gst_asm_scan_next_token (scan); |
| |
| node->right = gst_asm_scan_parse_expression (scan); |
| node->left = left; |
| } |
| return node; |
| } |
| |
| static void |
| gst_asm_scan_parse_property (GstASMRule * rule, GstASMScan * scan) |
| { |
| gchar *key, *val; |
| |
| if (scan->token != GST_ASM_TOKEN_IDENTIFIER) { |
| g_warning ("identifier expected"); |
| return; |
| } |
| key = g_strdup (scan->val); |
| |
| gst_asm_scan_next_token (scan); |
| if (scan->token != GST_ASM_TOKEN_EQUAL) { |
| g_warning ("= expected"); |
| return; |
| } |
| gst_asm_scan_next_token (scan); |
| val = g_strdup (scan->val); |
| |
| gst_asm_rule_add_property (rule, key, val); |
| gst_asm_scan_next_token (scan); |
| } |
| |
| static GstASMRule * |
| gst_asm_scan_parse_rule (GstASMScan * scan) |
| { |
| GstASMRule *rule; |
| |
| rule = gst_asm_rule_new (); |
| |
| if (scan->token == GST_ASM_TOKEN_HASH) { |
| gst_asm_scan_next_token (scan); |
| rule->root = gst_asm_scan_parse_condition (scan); |
| if (scan->token == GST_ASM_TOKEN_COMMA) |
| gst_asm_scan_next_token (scan); |
| } |
| |
| if (scan->token != GST_ASM_TOKEN_SEMICOLON) { |
| gst_asm_scan_parse_property (rule, scan); |
| while (scan->token == GST_ASM_TOKEN_COMMA) { |
| gst_asm_scan_next_token (scan); |
| gst_asm_scan_parse_property (rule, scan); |
| } |
| gst_asm_scan_next_token (scan); |
| } |
| return rule; |
| } |
| |
| static gboolean |
| gst_asm_rule_evaluate (GstASMRule * rule, GHashTable * vars) |
| { |
| gboolean res; |
| |
| if (rule->root) { |
| res = (gboolean) gst_asm_node_evaluate (rule->root, vars); |
| } else |
| res = TRUE; |
| |
| return res; |
| } |
| |
| GstASMRuleBook * |
| gst_asm_rule_book_new (const gchar * rulebook) |
| { |
| GstASMRuleBook *book; |
| GstASMRule *rule = NULL; |
| GstASMScan *scan; |
| GstASMToken token; |
| |
| book = g_new0 (GstASMRuleBook, 1); |
| book->rulebook = rulebook; |
| |
| scan = gst_asm_scan_new (book->rulebook); |
| gst_asm_scan_next_token (scan); |
| |
| do { |
| rule = gst_asm_scan_parse_rule (scan); |
| if (rule) { |
| book->rules = g_list_append (book->rules, rule); |
| book->n_rules++; |
| } |
| token = scan->token; |
| } while (token != GST_ASM_TOKEN_EOF); |
| |
| gst_asm_scan_free (scan); |
| |
| return book; |
| } |
| |
| void |
| gst_asm_rule_book_free (GstASMRuleBook * book) |
| { |
| GList *walk; |
| |
| for (walk = book->rules; walk; walk = g_list_next (walk)) { |
| GstASMRule *rule = (GstASMRule *) walk->data; |
| |
| gst_asm_rule_free (rule); |
| } |
| g_list_free (book->rules); |
| g_free (book); |
| } |
| |
| gint |
| gst_asm_rule_book_match (GstASMRuleBook * book, GHashTable * vars, |
| gint * rulematches) |
| { |
| GList *walk; |
| gint i, n = 0; |
| |
| for (walk = book->rules, i = 0; walk; walk = g_list_next (walk), i++) { |
| GstASMRule *rule = (GstASMRule *) walk->data; |
| |
| if (gst_asm_rule_evaluate (rule, vars)) { |
| rulematches[n++] = i; |
| } |
| } |
| return n; |
| } |
| |
| #ifdef TEST |
| gint |
| main (gint argc, gchar * argv[]) |
| { |
| GstASMRuleBook *book; |
| gint rulematch[MAX_RULEMATCHES]; |
| GHashTable *vars; |
| gint i, n; |
| |
| static const gchar rules1[] = |
| "#($Bandwidth < 67959),TimestampDelivery=T,DropByN=T," |
| "priority=9;#($Bandwidth >= 67959) && ($Bandwidth < 167959)," |
| "AverageBandwidth=67959,Priority=9;#($Bandwidth >= 67959) && ($Bandwidth" |
| " < 167959),AverageBandwidth=0,Priority=5,OnDepend=\\\"1\\\";#($Bandwidth >= 167959)" |
| " && ($Bandwidth < 267959),AverageBandwidth=167959,Priority=9;#($Bandwidth >= 167959)" |
| " && ($Bandwidth < 267959),AverageBandwidth=0,Priority=5,OnDepend=\\\"3\\\";" |
| "#($Bandwidth >= 267959),AverageBandwidth=267959,Priority=9;#($Bandwidth >= 267959)" |
| ",AverageBandwidth=0,Priority=5,OnDepend=\\\"5\\\";"; |
| static const gchar rules2[] = |
| "AverageBandwidth=32041,Priority=5;AverageBandwidth=0," |
| "Priority=5,OnDepend=\\\"0\\\", OffDepend=\\\"0\\\";"; |
| static const gchar rules3[] = |
| "#(($Bandwidth >= 27500) && ($OldPNMPlayer)),AverageBandwidth=27500,priority=9,PNMKeyframeRule=T;#(($Bandwidth >= 27500) && ($OldPNMPlayer)),AverageBandwidth=0,priority=5,PNMNonKeyframeRule=T;#(($Bandwidth < 27500) && ($OldPNMPlayer)),TimestampDelivery=T,DropByN=T,priority=9,PNMThinningRule=T;#($Bandwidth < 13899),TimestampDelivery=T,DropByN=T,priority=9;#($Bandwidth >= 13899) && ($Bandwidth < 19000),AverageBandwidth=13899,Priority=9;#($Bandwidth >= 13899) && ($Bandwidth < 19000),AverageBandwidth=0,Priority=5,OnDepend=\\\"4\\\";#($Bandwidth >= 19000) && ($Bandwidth < 27500),AverageBandwidth=19000,Priority=9;#($Bandwidth >= 19000) && ($Bandwidth < 27500),AverageBandwidth=0,Priority=5,OnDepend=\\\"6\\\";#($Bandwidth >= 27500) && ($Bandwidth < 132958),AverageBandwidth=27500,Priority=9;#($Bandwidth >= 27500) && ($Bandwidth < 132958),AverageBandwidth=0,Priority=5,OnDepend=\\\"8\\\";#($Bandwidth >= 132958) && ($Bandwidth < 187958),AverageBandwidth=132958,Priority=9;#($Bandwidth >= 132958) && ($Bandwidth < 187958),AverageBandwidth=0,Priority=5,OnDepend=\\\"10\\\";#($Bandwidth >= 187958),AverageBandwidth=187958,Priority=9;#($Bandwidth >= 187958),AverageBandwidth=0,Priority=5,OnDepend=\\\"12\\\";"; |
| |
| vars = g_hash_table_new (g_str_hash, g_str_equal); |
| g_hash_table_insert (vars, (gchar *) "Bandwidth", (gchar *) "300000"); |
| |
| book = gst_asm_rule_book_new (rules1); |
| n = gst_asm_rule_book_match (book, vars, rulematch); |
| gst_asm_rule_book_free (book); |
| |
| g_print ("%d rules matched\n", n); |
| for (i = 0; i < n; i++) { |
| g_print ("rule %d matched\n", rulematch[i]); |
| } |
| |
| book = gst_asm_rule_book_new (rules2); |
| n = gst_asm_rule_book_match (book, vars, rulematch); |
| gst_asm_rule_book_free (book); |
| |
| g_print ("%d rules matched\n", n); |
| for (i = 0; i < n; i++) { |
| g_print ("rule %d matched\n", rulematch[i]); |
| } |
| |
| book = gst_asm_rule_book_new (rules3); |
| n = gst_asm_rule_book_match (book, vars, rulematch); |
| gst_asm_rule_book_free (book); |
| |
| |
| g_print ("%d rules matched\n", n); |
| for (i = 0; i < n; i++) { |
| g_print ("rule %d matched\n", rulematch[i]); |
| } |
| |
| g_hash_table_destroy (vars); |
| |
| return 0; |
| } |
| #endif |