~ubuntu-branches/debian/lenny/net-snmp/lenny

« back to all changes in this revision

Viewing changes to agent/mibgroup/disman/expr/expValue.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-05-10 22:20:23 UTC
  • Revision ID: james.westby@ubuntu.com-20070510222023-3fr07xb9i17xvq32
Tags: upstream-5.3.1
ImportĀ upstreamĀ versionĀ 5.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DisMan Expression MIB:
 
3
 *    Core implementation of expression evaluation
 
4
 */
 
5
 
 
6
#include <net-snmp/net-snmp-config.h>
 
7
#include <net-snmp/net-snmp-includes.h>
 
8
#include <net-snmp/agent/net-snmp-agent-includes.h>
 
9
#include "disman/expr/expExpression.h"
 
10
#include "disman/expr/expObject.h"
 
11
#include "disman/expr/expValue.h"
 
12
 
 
13
#include <ctype.h>
 
14
 
 
15
void _expValue_setError( struct expExpression *exp, int reason,
 
16
                         oid *suffix, size_t suffix_len,
 
17
                         netsnmp_variable_list *var);
 
18
 
 
19
 
 
20
#define ASN_PRIV_OPERATOR    (ASN_PRIVATE | 0x0f)
 
21
#define ASN_PRIV_FUNCTION    (ASN_PRIVATE | 0x0e)
 
22
 
 
23
int ops[128];   /* mapping from operator characters to numeric
 
24
                   tokens (ordered by priority). */
 
25
 
 
26
 
 
27
init_expValue(void)
 
28
{
 
29
DEBUGMSGTL(("disman:expr:eval", "Init expValue"));
 
30
        /* Single-character operators */
 
31
    ops['+'] = EXP_OPERATOR_ADD;
 
32
    ops['-'] = EXP_OPERATOR_SUBTRACT;
 
33
    ops['*'] = EXP_OPERATOR_MULTIPLY;
 
34
    ops['/'] = EXP_OPERATOR_DIVIDE;
 
35
    ops['%'] = EXP_OPERATOR_REMAINDER;
 
36
    ops['^'] = EXP_OPERATOR_BITXOR;
 
37
    ops['~'] = EXP_OPERATOR_BITNEGATE;
 
38
    ops['|'] = EXP_OPERATOR_BITOR;
 
39
    ops['&'] = EXP_OPERATOR_BITAND;
 
40
    ops['!'] = EXP_OPERATOR_NOT;
 
41
    ops['<'] = EXP_OPERATOR_LESS;
 
42
    ops['>'] = EXP_OPERATOR_GREAT;
 
43
 
 
44
                                         /*
 
45
                                          * Arbitrary offsets, chosen so
 
46
                                          * the three blocks don't overlap.
 
47
                                          */
 
48
        /* "X=" operators */
 
49
    ops['='+20] = EXP_OPERATOR_EQUAL;
 
50
    ops['!'+20] = EXP_OPERATOR_NOTEQ;
 
51
    ops['<'+20] = EXP_OPERATOR_LESSEQ;
 
52
    ops['>'+20] = EXP_OPERATOR_GREATEQ;
 
53
 
 
54
        /* "XX" operators */
 
55
    ops['|'-30] = EXP_OPERATOR_OR;
 
56
    ops['&'-30] = EXP_OPERATOR_AND;
 
57
    ops['<'-30] = EXP_OPERATOR_LSHIFT;
 
58
    ops['>'-30] = EXP_OPERATOR_RSHIFT;
 
59
}
 
60
 
 
61
    /*
 
62
     * Insert the value of the specified object parameter,
 
63
     * using the instance 'suffix' for wildcarded objects.
 
64
     */
 
65
netsnmp_variable_list *
 
66
_expValue_evalParam( netsnmp_variable_list *expIdx, int param,
 
67
                     oid *suffix, size_t suffix_len )
 
68
{
 
69
    netsnmp_variable_list *var = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
 
70
    struct expObject  *obj;
 
71
    netsnmp_variable_list *val_var  = NULL, *oval_var = NULL;  /* values  */
 
72
    netsnmp_variable_list *dd_var   = NULL,  *odd_var = NULL;  /* deltaDs */
 
73
    netsnmp_variable_list *cond_var = NULL;               /* conditionals */
 
74
    int n;
 
75
 
 
76
    /*
 
77
     * Retrieve the expObject entry for the requested parameter.
 
78
     */
 
79
    if ( !var || !expIdx || !expIdx->next_variable ||
 
80
                 !expIdx->next_variable->next_variable )
 
81
        return NULL;
 
82
 
 
83
    *expIdx->next_variable->next_variable->val.integer = param;
 
84
    obj = (struct expObject *)
 
85
               netsnmp_tdata_row_entry(
 
86
                   netsnmp_tdata_row_get_byidx( expObject_table_data, expIdx ));
 
87
    if (!obj) {
 
88
        /*
 
89
         * No such parameter configured for this expression
 
90
         */
 
91
        snmp_set_var_typed_integer( var, ASN_INTEGER, EXPERRCODE_INDEX );
 
92
        var->type = ASN_NULL;
 
93
        return var;
 
94
    }
 
95
    if ( obj->expObjectSampleType != EXPSAMPLETYPE_ABSOLUTE &&
 
96
         obj->old_vars == NULL ) {
 
97
        /*
 
98
         * Can't calculate delta values until the second pass
 
99
         */
 
100
        snmp_set_var_typed_integer( var, ASN_INTEGER, EXPERRCODE_RESOURCE );
 
101
        var->type = ASN_NULL;
 
102
        return var;
 
103
    }
 
104
 
 
105
 
 
106
    /*
 
107
     * For a wildcarded object, search for the matching suffix.
 
108
     */
 
109
    val_var = obj->vars;
 
110
    if ( obj->flags & EXP_OBJ_FLAG_OWILD ) {
 
111
        if ( !suffix ) {
 
112
            /*
 
113
             * If there's no suffix to match against, throw an error.
 
114
             * An exact expression with a wildcarded object is invalid.
 
115
             *   XXX - Or just use first entry?
 
116
             */
 
117
            snmp_set_var_typed_integer( var, ASN_INTEGER, EXPERRCODE_INDEX );
 
118
            var->type = ASN_NULL;
 
119
            return var;
 
120
        }
 
121
        /*
 
122
         * Otherwise, we'll walk *all* wildcarded values in parallel.
 
123
         * This relies on the various varbind lists being set up with
 
124
         *   exactly the same entries.  A little extra preparation
 
125
         *   during the data gathering simplifies things significantly!
 
126
         */
 
127
        if ( obj->expObjectSampleType != EXPSAMPLETYPE_ABSOLUTE )
 
128
            oval_var = obj->old_vars;
 
129
        if ( obj->flags & EXP_OBJ_FLAG_DWILD ) {
 
130
            dd_var   = obj->dvars;
 
131
            odd_var  = obj->old_dvars;
 
132
        }
 
133
        if ( obj->flags & EXP_OBJ_FLAG_CWILD )
 
134
            cond_var = obj->cvars;
 
135
       
 
136
        n = obj->expObjectID_len;
 
137
        while ( val_var ) {
 
138
            if ( snmp_oid_compare( val_var->name+n, val_var->name_length-n,
 
139
                                   suffix, suffix_len ))
 
140
                break;
 
141
            val_var = val_var->next_variable;
 
142
            if (oval_var)
 
143
                oval_var = oval_var->next_variable;
 
144
            if (dd_var) {
 
145
                dd_var   =  dd_var->next_variable;
 
146
                odd_var  = odd_var->next_variable;
 
147
            }
 
148
            if (cond_var)
 
149
                cond_var = cond_var->next_variable;
 
150
        }
 
151
 
 
152
    }
 
153
    if (!val_var) {
 
154
        /*
 
155
         * No matching entry
 
156
         */
 
157
        snmp_set_var_typed_integer( var, ASN_INTEGER, EXPERRCODE_INDEX );
 
158
        var->type = ASN_NULL;
 
159
        return var;
 
160
    }
 
161
        /*
 
162
         * Set up any non-wildcarded values - some
 
163
         *   of which may be null. That's fine.
 
164
         */
 
165
    if (!oval_var)
 
166
        oval_var = obj->old_vars;
 
167
    if (!dd_var) {
 
168
        dd_var   = obj->dvars;
 
169
        odd_var  = obj->old_dvars;
 
170
    }
 
171
    if (!cond_var)
 
172
        cond_var = obj->cvars;
 
173
    
 
174
 
 
175
    /*
 
176
     * ... and return the appropriate value.
 
177
     */
 
178
    if (obj->expObjCond_len &&
 
179
        (!cond_var || *cond_var->val.integer == 0)) {
 
180
        /*
 
181
         * expObjectConditional says no
 
182
         */
 
183
        snmp_set_var_typed_integer( var, ASN_INTEGER, EXPERRCODE_INDEX );
 
184
        var->type = ASN_NULL;
 
185
        return var;
 
186
    }
 
187
    if (dd_var && odd_var &&
 
188
        *dd_var->val.integer != *odd_var->val.integer) {
 
189
        /*
 
190
         * expObjectDeltaD says no
 
191
         */
 
192
        snmp_set_var_typed_integer( var, ASN_INTEGER, EXPERRCODE_INDEX );
 
193
        var->type = ASN_NULL;
 
194
        return var;
 
195
    }
 
196
 
 
197
    /*
 
198
     * XXX - May need to check sysUpTime discontinuities
 
199
     *            (unless this is handled earlier....)
 
200
     */
 
201
    switch ( obj->expObjectSampleType ) {
 
202
    case EXPSAMPLETYPE_ABSOLUTE:
 
203
        snmp_clone_var( val_var, var );
 
204
        break;
 
205
    case EXPSAMPLETYPE_DELTA:
 
206
        snmp_set_var_typed_integer( var, ASN_INTEGER /* or UNSIGNED? */,
 
207
                              *val_var->val.integer - *oval_var->val.integer );
 
208
        break;
 
209
    case EXPSAMPLETYPE_CHANGED:
 
210
        if ( val_var->val_len != oval_var->val_len )
 
211
            n = 1;
 
212
        else if (memcmp( val_var->val.string, oval_var->val.string,
 
213
                                               val_var->val_len ) != 0 )
 
214
            n = 1;
 
215
        else
 
216
            n = 0;
 
217
        snmp_set_var_typed_integer( var, ASN_UNSIGNED, n );
 
218
    }
 
219
    return var;
 
220
}
 
221
 
 
222
 
 
223
    /*
 
224
     * Utility routine to parse (and skip over) an integer constant
 
225
     */
 
226
int
 
227
_expParse_integer( char *start, char **end ) {
 
228
    int n;
 
229
    char *cp;
 
230
 
 
231
    n = atoi(start);
 
232
    for (cp=start; *cp; cp++)
 
233
        if (!isdigit(*cp))
 
234
            break;
 
235
    *end = cp;
 
236
    return n;
 
237
}
 
238
 
 
239
netsnmp_variable_list *
 
240
_expValue_evalOperator(netsnmp_variable_list *left, 
 
241
                       netsnmp_variable_list *op, 
 
242
                       netsnmp_variable_list *right) {
 
243
    int n;
 
244
 
 
245
    switch( *op->val.integer ) {
 
246
    case EXP_OPERATOR_ADD:
 
247
        n = *left->val.integer + *right->val.integer; break;
 
248
    case EXP_OPERATOR_SUBTRACT:
 
249
        n = *left->val.integer - *right->val.integer; break;
 
250
    case EXP_OPERATOR_MULTIPLY:
 
251
        n = *left->val.integer * *right->val.integer; break;
 
252
    case EXP_OPERATOR_DIVIDE:
 
253
        n = *left->val.integer / *right->val.integer; break;
 
254
    case EXP_OPERATOR_REMAINDER:
 
255
        n = *left->val.integer % *right->val.integer; break;
 
256
    case EXP_OPERATOR_BITXOR:
 
257
        n = *left->val.integer ^ *right->val.integer; break;
 
258
    case EXP_OPERATOR_BITNEGATE:
 
259
        n = 99; /* *left->val.integer ~ *right->val.integer; */ break;
 
260
    case EXP_OPERATOR_BITOR:
 
261
        n = *left->val.integer | *right->val.integer; break;
 
262
    case EXP_OPERATOR_BITAND:
 
263
        n = *left->val.integer & *right->val.integer; break;
 
264
    case EXP_OPERATOR_NOT:
 
265
        n = 99; /* *left->val.integer ! *right->val.integer; */ break;
 
266
    case EXP_OPERATOR_LESS:
 
267
        n = *left->val.integer < *right->val.integer; break;
 
268
    case EXP_OPERATOR_GREAT:
 
269
        n = *left->val.integer > *right->val.integer; break;
 
270
    case EXP_OPERATOR_EQUAL:
 
271
        n = *left->val.integer == *right->val.integer; break;
 
272
    case EXP_OPERATOR_NOTEQ:
 
273
        n = *left->val.integer != *right->val.integer; break;
 
274
    case EXP_OPERATOR_LESSEQ:
 
275
        n = *left->val.integer <= *right->val.integer; break;
 
276
    case EXP_OPERATOR_GREATEQ:
 
277
        n = *left->val.integer >= *right->val.integer; break;
 
278
    case EXP_OPERATOR_OR:
 
279
        n = *left->val.integer || *right->val.integer; break;
 
280
    case EXP_OPERATOR_AND:
 
281
        n = *left->val.integer && *right->val.integer; break;
 
282
    case EXP_OPERATOR_LSHIFT:
 
283
        n = *left->val.integer << *right->val.integer; break;
 
284
    case EXP_OPERATOR_RSHIFT:
 
285
        n = *left->val.integer >> *right->val.integer; break;
 
286
        break;
 
287
    default:
 
288
        left->next_variable = NULL;
 
289
        snmp_free_var(left);
 
290
        right->next_variable = NULL;
 
291
        snmp_free_var(right);
 
292
 
 
293
        snmp_set_var_typed_integer( op, ASN_INTEGER, EXPERRCODE_OPERATOR );
 
294
        op->type = ASN_NULL;
 
295
        return op;
 
296
    }
 
297
 
 
298
    /* XXX */
 
299
    left->next_variable = NULL;
 
300
    snmp_free_var(left);
 
301
    op->next_variable = NULL;
 
302
    snmp_free_var(op);
 
303
    snmp_set_var_typed_integer( right, ASN_INTEGER, n );
 
304
    return right;
 
305
}
 
306
 
 
307
netsnmp_variable_list *
 
308
_expValue_evalFunction(netsnmp_variable_list *func) {
 
309
    netsnmp_variable_list *params = func->next_variable;
 
310
    /* XXX */
 
311
    params->next_variable = NULL;
 
312
    snmp_free_var(params);
 
313
    snmp_set_var_typed_integer( func, ASN_INTEGER, 99 );
 
314
    return func;
 
315
}
 
316
 
 
317
netsnmp_variable_list *_expValue_evalExpr2(netsnmp_variable_list *exprAlDente);
 
318
netsnmp_variable_list *
 
319
_expValue_evalExpr(  netsnmp_variable_list *expIdx,
 
320
                     char *exprRaw, char **exprEnd,
 
321
                     oid *suffix, size_t suffix_len )
 
322
{
 
323
    netsnmp_variable_list *exprAlDente = NULL;
 
324
    netsnmp_variable_list *vtail = NULL;
 
325
    char *cp1, *cp2, *cp3;
 
326
    netsnmp_variable_list *var = NULL;
 
327
    int   i, n, level;
 
328
    int   neg = 0;
 
329
    oid   oid_buf[MAX_OID_LEN];
 
330
 
 
331
    DEBUGMSGTL(("disman:expr:eval1", "Evaluating '%s'\n", exprRaw));
 
332
    if (!expIdx || !exprRaw)
 
333
        return NULL;
 
334
 
 
335
    /*
 
336
     * The expression is evaluated in two stages.
 
337
     * First, we simplify ("parboil") the raw expression,
 
338
     *   tokenizing it into a sequence of varbind values, inserting
 
339
     *   object parameters, and (recursively) evaluating any
 
340
     *   parenthesised sub-expressions or function arguments.
 
341
     */
 
342
 
 
343
    for (cp1=exprRaw; cp1 && *cp1; ) {
 
344
        switch (*cp1) {
 
345
        case '$':
 
346
            /*
 
347
             * Locate the appropriate instance of the specified
 
348
             * parameter, and insert the corresponding value.
 
349
             */
 
350
            n   = _expParse_integer( cp1+1, &cp1 );
 
351
            var = _expValue_evalParam( expIdx, n, suffix, suffix_len );
 
352
            if ( var && var->type == ASN_NULL ) {
 
353
                DEBUGMSGTL(("disman:expr:eval", "Invalid parameter '%d'\n", n));
 
354
                /* Note position of failure in expression */
 
355
                var->data = (void *)(cp1 - exprRaw);
 
356
                snmp_free_var(exprAlDente);
 
357
                return var;
 
358
            } else {
 
359
                if (vtail)
 
360
                   vtail->next_variable = var;
 
361
                else
 
362
                   exprAlDente = var;
 
363
                vtail = var;
 
364
                var   = NULL;
 
365
            }
 
366
            break;
 
367
        case '(':
 
368
            /*
 
369
             * Recursively evaluate the sub-expression
 
370
             */
 
371
            var = _expValue_evalExpr( expIdx, cp1+1, &cp2,
 
372
                                      suffix, suffix_len );
 
373
            if ( var && var->type == ASN_NULL ) {
 
374
                /* Adjust position of failure */
 
375
                var->data = (void *)(cp1 - exprRaw + (int)var->data);
 
376
                return var;
 
377
            } else if (*cp2 != ')') {
 
378
                snmp_free_var(exprAlDente);
 
379
                DEBUGMSGTL(("disman:expr:eval", "Unbalanced parenthesis\n"));
 
380
                snmp_set_var_typed_integer( var, ASN_INTEGER,
 
381
                                            EXPERRCODE_PARENTHESIS );
 
382
                var->type = ASN_NULL;
 
383
                var->data = (void *)(cp2 - exprRaw);
 
384
                return var;
 
385
            } else {
 
386
                if (vtail)
 
387
                   vtail->next_variable = var;
 
388
                else
 
389
                   exprAlDente = var;
 
390
                vtail = var;
 
391
                var   = NULL;
 
392
                cp1   = cp2+1;   /* Skip to end of sub-expression */
 
393
            }
 
394
            break;
 
395
        case ')':
 
396
        case ',':
 
397
            /*
 
398
             * End of current (sub-)expression
 
399
             * Note the end-position, and evaluate
 
400
             *  the parboiled list of tokens.
 
401
             */
 
402
            *exprEnd = cp1;
 
403
            var = _expValue_evalExpr2( exprAlDente );
 
404
            snmp_free_var(exprAlDente);
 
405
            return var;
 
406
 
 
407
            /* === Constants === */
 
408
        case '.':   /* OID */
 
409
            i = 0;
 
410
            memset( oid_buf, 0, sizeof(oid_buf));
 
411
            while ( cp1 && *cp1 == '.' ) {
 
412
                n = _expParse_integer( cp1+1, &cp2 );
 
413
OID:
 
414
                oid_buf[i++] = n;
 
415
                cp1 = cp2;
 
416
            }
 
417
            var = snmp_varlist_add_variable( &exprAlDente, NULL, 0,
 
418
                                             ASN_OBJECT_ID,
 
419
                                             (u_char*)oid_buf, i*sizeof(oid));
 
420
            break;
 
421
DIGIT:
 
422
        case '0':
 
423
        case '1':
 
424
        case '2':
 
425
        case '3':
 
426
        case '4':
 
427
        case '5':
 
428
        case '6':
 
429
        case '7':
 
430
        case '8':
 
431
        case '9':
 
432
            n = _expParse_integer( cp1, &cp2 );
 
433
            if ( cp2 && *cp2 == '.' ) {
 
434
                i = 0;
 
435
                memset( oid_buf, 0, sizeof(oid_buf));
 
436
                goto OID;
 
437
            }
 
438
            if ( neg )
 
439
                n = -n;
 
440
            var = snmp_varlist_add_variable( &exprAlDente, NULL, 0,
 
441
                                             ASN_INTEGER,
 
442
                                             (u_char*)&n, sizeof(n));
 
443
            vtail = var;
 
444
            var   = NULL;
 
445
            neg   = 0;
 
446
            cp1   = cp2;
 
447
            break;
 
448
 
 
449
        case '"':   /* String Constant */
 
450
            for ( cp2 = cp1+1; *cp2; cp2++ ) {
 
451
                if ( *cp2 == '"' )
 
452
                    break;
 
453
                if ( *cp2 == '\\' && *(cp2+1) == '"' )
 
454
                    cp2++;
 
455
            }
 
456
            if ( *cp2 != '"' ) {
 
457
                /*
 
458
                 * Unterminated string
 
459
                 */
 
460
                DEBUGMSGTL(("disman:expr:eval", "Unterminated string\n"));
 
461
                snmp_set_var_typed_integer( var, ASN_INTEGER,
 
462
                                            EXPERRCODE_SYNTAX );
 
463
                var->type = ASN_NULL;
 
464
                var->data = (void *)(cp2 - exprRaw);
 
465
                return var;
 
466
            }
 
467
            n = cp2 - cp1;  
 
468
            var = snmp_varlist_add_variable( &exprAlDente, NULL, 0,
 
469
                                             ASN_OCTET_STR,
 
470
                                             (u_char*)cp1+1, n);
 
471
            vtail = var;
 
472
            var   = NULL;
 
473
            break;
 
474
 
 
475
 
 
476
            /* === Operators === */
 
477
        case '-':
 
478
            /*
 
479
             * Could be a unary minus....
 
480
             */
 
481
            if (!vtail || vtail->type == ASN_PRIV_OPERATOR) {
 
482
                neg = 1;
 
483
                goto DIGIT;
 
484
            }
 
485
            /* 
 
486
             * ... or a (single-character) binary operator.
 
487
             */
 
488
            /* Fallthrough */
 
489
        case '+':
 
490
        case '*':
 
491
        case '/':
 
492
        case '%':
 
493
        case '^':
 
494
        case '~':
 
495
            if ( !vtail ) {
 
496
                /*
 
497
                 * Can't start an expression with a binary operator
 
498
                 */
 
499
                DEBUGMSGTL(("disman:expr:eval", "Initial binary operator\n"));
 
500
                snmp_set_var_typed_integer( var, ASN_INTEGER,
 
501
                                            EXPERRCODE_SYNTAX );
 
502
                var->type = ASN_NULL;
 
503
                var->data = (void *)(cp1 - exprRaw);
 
504
                return var;
 
505
            }
 
506
            n = ops[ *cp1 ];
 
507
            DEBUGMSGTL(("disman:expr:eval", "Binary operator %c (%d)\n", *cp1, n));
 
508
            var = snmp_varlist_add_variable( &exprAlDente, NULL, 0,
 
509
                                             ASN_INTEGER,
 
510
                                             (u_char*)&n, sizeof(n));
 
511
            var->type = ASN_PRIV_OPERATOR;
 
512
            vtail = var;
 
513
            cp1++;
 
514
            break;
 
515
 
 
516
            /* 
 
517
             * Multi-character binary operators
 
518
             */
 
519
        case '&':
 
520
        case '|':
 
521
        case '!':
 
522
        case '>':
 
523
        case '<':
 
524
        case '=':
 
525
            if ( !vtail ) {
 
526
                /*
 
527
                 * Can't start an expression with a binary operator
 
528
                 */
 
529
                DEBUGMSGTL(("disman:expr:eval", "Initial binary operator\n"));
 
530
                snmp_set_var_typed_integer( var, ASN_INTEGER,
 
531
                                            EXPERRCODE_SYNTAX );
 
532
                var->type = ASN_NULL;
 
533
                var->data = (void *)(cp1 - exprRaw);
 
534
                return var;
 
535
            }
 
536
            if ( *(cp1+1) == '=' )
 
537
                n = ops[ *cp1++ + 20];
 
538
            else if ( *(cp1+1) == *cp1 )
 
539
                n = ops[ *cp1++ - 30];
 
540
            else
 
541
                n = ops[ *cp1 ];
 
542
            var = snmp_varlist_add_variable( &exprAlDente, NULL, 0,
 
543
                                             ASN_INTEGER,
 
544
                                             (u_char*)&n, sizeof(n));
 
545
            var->type = ASN_PRIV_OPERATOR;
 
546
            vtail = var;
 
547
            cp1++;
 
548
            break;
 
549
 
 
550
            /* === Functions === */
 
551
        case 'a':    /* average/arraySection */
 
552
        case 'c':    /* counter32/counter64  */
 
553
        case 'e':    /*    exists            */
 
554
        case 'm':    /* maximum/minimum      */
 
555
        case 'o':    /* oidBegins/Ends/Contains    */
 
556
        case 's':    /* sum / string{B,E,C}  */
 
557
            var = snmp_varlist_add_variable( &exprAlDente, NULL, 0,
 
558
                                             ASN_OCTET_STR,
 
559
                                             (u_char*)cp1, 3 );
 
560
                                                   /* XXX */
 
561
            var->type = ASN_PRIV_FUNCTION;
 
562
            vtail = var;
 
563
            while (*cp1 >= 'a' && *cp1 <= 'z')
 
564
              cp1++;
 
565
            break;
 
566
 
 
567
        default:
 
568
            if (isalpha( *cp1 )) {
 
569
                /*
 
570
                 * Unrecognised function call ?
 
571
                 */
 
572
                DEBUGMSGTL(("disman:expr:eval", "Unrecognised function '%s'\n", cp1));
 
573
                snmp_set_var_typed_integer( var, ASN_INTEGER,
 
574
                                            EXPERRCODE_FUNCTION );
 
575
                var->type = ASN_NULL;
 
576
                var->data = (void *)(cp1 - exprRaw);
 
577
                return var;
 
578
            }
 
579
            else if (!isspace( *cp1 )) {
 
580
                /*
 
581
                 * Unrecognised operator ?
 
582
                 */
 
583
                DEBUGMSGTL(("disman:expr:eval", "Unrecognised operator '%c'\n", *cp1));
 
584
                snmp_set_var_typed_integer( var, ASN_INTEGER,
 
585
                                            EXPERRCODE_OPERATOR );
 
586
                var->type = ASN_NULL;
 
587
                var->data = (void *)(cp1 - exprRaw);
 
588
                return var;
 
589
            }
 
590
            cp1++;
 
591
            break;
 
592
        }
 
593
    }
 
594
 
 
595
    /*
 
596
     * ... then we evaluate the resulting simplified ("al dente")
 
597
     *   expression, in the usual manner.
 
598
     */
 
599
    *exprEnd = cp1;
 
600
    var = _expValue_evalExpr2( exprAlDente );
 
601
    DEBUGMSGTL(( "disman:expr:eval1", "Evaluated to "));
 
602
    DEBUGMSGVAR(("disman:expr:eval1", var));
 
603
    DEBUGMSG((   "disman:expr:eval1", "\n"));
 
604
/*  snmp_free_var(exprAlDente); XXX - Crashes */
 
605
    return var;
 
606
}
 
607
 
 
608
netsnmp_variable_list *
 
609
_expValue_evalExpr2( netsnmp_variable_list *exprAlD )
 
610
{
 
611
    netsnmp_variable_list *stack = NULL;
 
612
    netsnmp_variable_list *lval, *rval, *op;
 
613
    netsnmp_variable_list *vp, *vp1  = NULL;
 
614
 
 
615
    DEBUGIF(( "disman:expr:eval2")) {
 
616
        for (vp = exprAlD; vp; vp=vp->next_variable) {
 
617
            if ( vp->type == ASN_PRIV_OPERATOR )
 
618
                DEBUGMSGTL(( "disman:expr:eval2", "Operator %d\n",
 
619
                                                  *vp->val.integer));
 
620
            else if ( vp->type == ASN_PRIV_FUNCTION )
 
621
                DEBUGMSGTL(( "disman:expr:eval2", "Function %s\n",
 
622
                                                   vp->val.string));
 
623
            else {
 
624
                DEBUGMSGTL(( "disman:expr:eval2", "Operand "));
 
625
                DEBUGMSGVAR(("disman:expr:eval2", vp));
 
626
                DEBUGMSG((   "disman:expr:eval2", "\n"));
 
627
            }
 
628
        }
 
629
    }
 
630
    
 
631
    for (vp = exprAlD; vp; vp=vp1) {
 
632
        vp1 = vp->next_variable;
 
633
        if ( vp->type == ASN_PRIV_OPERATOR ) {
 
634
            /* Must *always* follow a value */
 
635
            if ( !stack || stack->type == ASN_PRIV_OPERATOR ) {
 
636
                snmp_set_var_typed_integer( vp, ASN_INTEGER,
 
637
                                            EXPERRCODE_SYNTAX );
 
638
                vp->type = ASN_NULL;
 
639
                snmp_free_var( stack );
 
640
                return vp;
 
641
            }
 
642
            /*
 
643
             * Evaluate any higher priority operators
 
644
             *  already on the stack....
 
645
             */
 
646
            while ( stack->next_variable &&
 
647
                    stack->next_variable->type == ASN_PRIV_OPERATOR &&
 
648
                  (*stack->next_variable->val.integer > *vp->val.integer)) {
 
649
                 rval = stack;
 
650
                 op   = stack->next_variable;
 
651
                 lval = op->next_variable;
 
652
                 stack = lval->next_variable;
 
653
 
 
654
                 rval = _expValue_evalOperator( lval, op, rval );
 
655
                 rval->next_variable = stack;
 
656
                 stack = rval;
 
657
            }
 
658
            /*
 
659
             * ... and then push this operator onto the stack.
 
660
             */
 
661
            vp->next_variable = stack;
 
662
            stack = vp;
 
663
        } else if ( vp->type == ASN_PRIV_FUNCTION ) {
 
664
            /* Must be first, or follow an operator */
 
665
            if ( stack && stack->type != ASN_PRIV_OPERATOR ) {
 
666
                snmp_set_var_typed_integer( vp, ASN_INTEGER,
 
667
                                            EXPERRCODE_SYNTAX );
 
668
                vp->type = ASN_NULL;
 
669
                snmp_free_var( stack );
 
670
                return vp;
 
671
            }
 
672
            /*
 
673
             * Evaluate this function (consuming the
 
674
             *   appropriate parameters from the token 
 
675
             *   list), and push the result onto the stack.
 
676
             */
 
677
            vp = _expValue_evalFunction( vp );
 
678
            vp1 = vp->next_variable;
 
679
            vp->next_variable = stack;
 
680
            stack = vp;
 
681
        } else {
 
682
            /* Must be first, or follow an operator */
 
683
            if ( stack && stack->type != ASN_PRIV_OPERATOR ) {
 
684
                snmp_set_var_typed_integer( vp, ASN_INTEGER,
 
685
                                            EXPERRCODE_SYNTAX );
 
686
                vp->type = ASN_NULL;
 
687
                snmp_free_var( stack );
 
688
                return vp;
 
689
            }
 
690
            /*
 
691
             * Push this value onto the stack
 
692
             */
 
693
            vp->next_variable = stack;
 
694
            stack = vp;
 
695
        }
 
696
    }
 
697
 
 
698
    /*
 
699
     * Now evaluate whatever's left on the stack
 
700
     *   and return the final result.
 
701
     */
 
702
    while ( stack && stack->next_variable ) {
 
703
        rval = stack;
 
704
        op   = stack->next_variable;
 
705
        lval = op->next_variable;
 
706
        stack = lval->next_variable;
 
707
 
 
708
        rval = _expValue_evalOperator( lval, op, rval );
 
709
        rval->next_variable = stack;
 
710
        stack = rval;
 
711
    }
 
712
    return stack;
 
713
}
 
714
 
 
715
/* =============
 
716
 *  Main API 
 
717
 * ============= */
 
718
netsnmp_variable_list *
 
719
expValue_evaluateExpression( struct expExpression *exp,
 
720
                             oid *suffix, size_t suffix_len )
 
721
{
 
722
    char exprRaw[     EXP_STR3_LEN+1 ];
 
723
    netsnmp_variable_list *var;
 
724
    netsnmp_variable_list owner_var, name_var, param_var;
 
725
    long n;
 
726
    char *cp;
 
727
 
 
728
    if (!exp)
 
729
        return NULL;
 
730
 
 
731
    /*
 
732
     * Set up a varbind list containing the various index values
 
733
     *   (including a placeholder for expObjectIndex).
 
734
     *
 
735
     * This saves having to construct the same index list repeatedly
 
736
     */
 
737
    memset(&owner_var, 0, sizeof(netsnmp_variable_list));
 
738
    memset(&name_var,  0, sizeof(netsnmp_variable_list));
 
739
    memset(&param_var, 0, sizeof(netsnmp_variable_list));
 
740
    snmp_set_var_typed_value( &owner_var, ASN_OCTET_STR,
 
741
                  (u_char*)exp->expOwner, strlen(exp->expOwner));
 
742
    snmp_set_var_typed_value( &name_var,  ASN_OCTET_STR,
 
743
                  (u_char*)exp->expName,  strlen(exp->expName));
 
744
    n = 99; /* dummy value */
 
745
    snmp_set_var_typed_value( &param_var, ASN_INTEGER,
 
746
                             (u_char*)&n, sizeof(long));
 
747
    owner_var.next_variable = &name_var;
 
748
    name_var.next_variable  = &param_var;
 
749
 
 
750
    /*
 
751
     * Make a working copy of the expression, and evaluate it.
 
752
     */
 
753
    memset(exprRaw, 0,                  sizeof(exprRaw));
 
754
    memcpy(exprRaw, exp->expExpression, sizeof(exprRaw));
 
755
 
 
756
    var = _expValue_evalExpr( &owner_var, exprRaw, &cp, suffix, suffix_len );
 
757
    /*
 
758
     * Check for any problems, and record the appropriate error
 
759
     */
 
760
    if (!cp || *cp != '\0') {
 
761
        /*
 
762
         * When we had finished, there was a lot
 
763
         * of bricks^Wcharacters left over....
 
764
         */
 
765
        _expValue_setError( exp, EXPERRCODE_SYNTAX, suffix, suffix_len, NULL );
 
766
        return NULL;
 
767
    }
 
768
    if (!var) {
 
769
        /* Shouldn't happen */
 
770
        _expValue_setError( exp, EXPERRCODE_RESOURCE, suffix, suffix_len, NULL );
 
771
        return NULL;
 
772
    }
 
773
    if (var->type == ASN_NULL) {
 
774
        /*
 
775
         * Error explicitly reported from the evaluation routines.
 
776
         */
 
777
        _expValue_setError( exp, *(var->val.integer), suffix, suffix_len, var );
 
778
        return NULL;
 
779
    }
 
780
    if (0 /* COMPARE var->type WITH exp->expValueType */ ) {
 
781
        /*
 
782
         * XXX - Check to see whether the returned type (ASN_XXX)
 
783
         *       is compatible with the requested type (an enum)
 
784
         */
 
785
 
 
786
        /* If not, throw an error */
 
787
        _expValue_setError( exp, EXPERRCODE_TYPE, suffix, suffix_len, var );
 
788
        return NULL;
 
789
    }
 
790
    return var;
 
791
}
 
792
 
 
793
void
 
794
_expValue_setError( struct expExpression *exp, int reason,
 
795
                    oid *suffix, size_t suffix_len,
 
796
                    netsnmp_variable_list *var)
 
797
{
 
798
    if (!exp)
 
799
        return;
 
800
    exp->expErrorCount++;
 
801
 /* exp->expErrorTime  = NOW; */
 
802
    exp->expErrorIndex = ( var && var->data ? (int)var->data : 0 );
 
803
    exp->expErrorCode  = reason;
 
804
    memset( exp->expErrorInstance, 0, sizeof(exp->expErrorInstance));
 
805
    memcpy( exp->expErrorInstance, suffix, suffix_len * sizeof(oid));
 
806
    exp->expErrorInst_len = suffix_len;
 
807
    snmp_free_var( var );
 
808
}