~ubuntu-branches/ubuntu/karmic/rsyslog/karmic

« back to all changes in this revision

Viewing changes to ctok.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2009-04-08 00:59:14 UTC
  • mfrom: (1.1.9 upstream) (3.2.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090408005914-gfyay7o45szt05zl
Tags: 3.20.5-1
* New upstream release.
* debian/rsyslog.logcheck.ignore.server
  - Install a logcheck ignore file for rsyslog (using dh_installlogcheck).
    Thanks to Kim Holviala for the patch. Closes: #522164

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* cfgtok.c - helper class to tokenize an input stream - which surprisingly
2
 
 * currently does not work with streams but with string. But that will
3
 
 * probably change over time ;) This class was originally written to support
4
 
 * the expression module but may evolve when (if) the expression module is
5
 
 * expanded (or aggregated) by a full-fledged ctoken based config parser.
6
 
 * Obviously, this class is used together with config files and not any other
7
 
 * parse function.
8
 
 *
9
 
 * Module begun 2008-02-19 by Rainer Gerhards
10
 
 *
11
 
 * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH.
12
 
 *
13
 
 * This file is part of the rsyslog runtime library.
14
 
 *
15
 
 * The rsyslog runtime library is free software: you can redistribute it and/or modify
16
 
 * it under the terms of the GNU Lesser General Public License as published by
17
 
 * the Free Software Foundation, either version 3 of the License, or
18
 
 * (at your option) any later version.
19
 
 *
20
 
 * The rsyslog runtime library is distributed in the hope that it will be useful,
21
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 
 * GNU Lesser General Public License for more details.
24
 
 *
25
 
 * You should have received a copy of the GNU Lesser General Public License
26
 
 * along with the rsyslog runtime library.  If not, see <http://www.gnu.org/licenses/>.
27
 
 *
28
 
 * A copy of the GPL can be found in the file "COPYING" in this distribution.
29
 
 * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
30
 
 */
31
 
 
32
 
#include "config.h"
33
 
#include <stdlib.h>
34
 
#include <ctype.h>
35
 
#include <strings.h>
36
 
#include <assert.h>
37
 
 
38
 
#include "rsyslog.h"
39
 
#include "template.h"
40
 
#include "ctok.h"
41
 
 
42
 
/* static data */
43
 
DEFobjStaticHelpers
44
 
DEFobjCurrIf(ctok_token)
45
 
DEFobjCurrIf(var)
46
 
 
47
 
 
48
 
/* Standard-Constructor
49
 
 */
50
 
BEGINobjConstruct(ctok) /* be sure to specify the object type also in END macro! */
51
 
ENDobjConstruct(ctok)
52
 
 
53
 
 
54
 
/* ConstructionFinalizer
55
 
 * rgerhards, 2008-01-09
56
 
 */
57
 
rsRetVal ctokConstructFinalize(ctok_t __attribute__((unused)) *pThis)
58
 
{
59
 
        DEFiRet;
60
 
        RETiRet;
61
 
}
62
 
 
63
 
 
64
 
/* destructor for the ctok object */
65
 
BEGINobjDestruct(ctok) /* be sure to specify the object type also in END and CODESTART macros! */
66
 
CODESTARTobjDestruct(ctok)
67
 
        /* ... then free resources */
68
 
ENDobjDestruct(ctok)
69
 
 
70
 
 
71
 
/* unget character from input stream. At most one character can be ungotten.
72
 
 * This funtion is only permitted to be called after at least one character
73
 
 * has been read from the stream. Right now, we handle the situation simply by
74
 
 * moving the string "stream" pointer one position backwards. If we work with
75
 
 * real streams (some time), the strm object will handle the functionality
76
 
 * itself. -- rgerhards, 2008-02-19
77
 
 */
78
 
static rsRetVal
79
 
ctokUngetCharFromStream(ctok_t *pThis, uchar __attribute__((unused)) c)
80
 
{
81
 
        DEFiRet;
82
 
 
83
 
        ISOBJ_TYPE_assert(pThis, ctok);
84
 
        --pThis->pp;
85
 
 
86
 
        RETiRet;
87
 
}
88
 
 
89
 
 
90
 
/* get the next character from the input "stream" (currently just a in-memory
91
 
 * string...) -- rgerhards, 2008-02-19
92
 
 */
93
 
static rsRetVal 
94
 
ctokGetCharFromStream(ctok_t *pThis, uchar *pc)
95
 
{
96
 
        DEFiRet;
97
 
 
98
 
        ISOBJ_TYPE_assert(pThis, ctok);
99
 
        ASSERT(pc != NULL);
100
 
 
101
 
        /* end of string or begin of comment terminates the "stream" */
102
 
        if(*pThis->pp == '\0' || *pThis->pp == '#') {
103
 
                ABORT_FINALIZE(RS_RET_EOS);
104
 
        } else {
105
 
                *pc = *pThis->pp;
106
 
                ++pThis->pp;
107
 
        }
108
 
 
109
 
finalize_it:
110
 
        RETiRet;
111
 
}
112
 
 
113
 
 
114
 
/* skip whitespace in the input "stream".
115
 
 * rgerhards, 2008-02-19
116
 
 */
117
 
static rsRetVal 
118
 
ctokSkipWhitespaceFromStream(ctok_t *pThis)
119
 
{
120
 
        DEFiRet;
121
 
        uchar c;
122
 
 
123
 
        ISOBJ_TYPE_assert(pThis, ctok);
124
 
 
125
 
        CHKiRet(ctokGetCharFromStream(pThis, &c));
126
 
        while(isspace(c)) {
127
 
                CHKiRet(ctokGetCharFromStream(pThis, &c));
128
 
        }
129
 
 
130
 
        /* we must unget the one non-whitespace we found */
131
 
        CHKiRet(ctokUngetCharFromStream(pThis, c));
132
 
 
133
 
dbgprintf("skipped whitepsace, stream now '%s'\n", pThis->pp);
134
 
finalize_it:
135
 
        RETiRet;
136
 
}
137
 
 
138
 
 
139
 
/* get the next word from the input "stream" (currently just a in-memory
140
 
 * string...). A word is anything from the current location until the
141
 
 * first non-alphanumeric character. If the word is longer
142
 
 * than the provided memory buffer, parsing terminates when buffer length
143
 
 * has been reached. A buffer of 128 bytes or more should always be by
144
 
 * far sufficient. -- rgerhards, 2008-02-19
145
 
 */
146
 
static rsRetVal 
147
 
ctokGetWordFromStream(ctok_t *pThis, uchar *pWordBuf, size_t lenWordBuf)
148
 
{
149
 
        DEFiRet;
150
 
        uchar c;
151
 
 
152
 
        ISOBJ_TYPE_assert(pThis, ctok);
153
 
        ASSERT(pWordBuf != NULL);
154
 
        ASSERT(lenWordBuf > 0);
155
 
 
156
 
        CHKiRet(ctokSkipWhitespaceFromStream(pThis));
157
 
 
158
 
        CHKiRet(ctokGetCharFromStream(pThis, &c));
159
 
        while((isalnum(c) || c == '_' || c == '-') && lenWordBuf > 1) {
160
 
                *pWordBuf++ = c;
161
 
                --lenWordBuf;
162
 
                CHKiRet(ctokGetCharFromStream(pThis, &c));
163
 
        }
164
 
        *pWordBuf = '\0'; /* there is always space for this - see while() */
165
 
 
166
 
        /* push back the char that we have read too much */
167
 
        CHKiRet(ctokUngetCharFromStream(pThis, c));
168
 
 
169
 
finalize_it:
170
 
        RETiRet;
171
 
}
172
 
 
173
 
 
174
 
/* read in a constant number
175
 
 * This is the "number" ABNF element
176
 
 * rgerhards, 2008-02-19
177
 
 */
178
 
static rsRetVal
179
 
ctokGetNumber(ctok_t *pThis, ctok_token_t *pToken)
180
 
{
181
 
        DEFiRet;
182
 
        number_t n; /* the parsed number */
183
 
        uchar c;
184
 
        int valC;
185
 
        int iBase;
186
 
 
187
 
        ISOBJ_TYPE_assert(pThis, ctok);
188
 
        ASSERT(pToken != NULL);
189
 
 
190
 
        pToken->tok = ctok_NUMBER;
191
 
 
192
 
        CHKiRet(ctokGetCharFromStream(pThis, &c));
193
 
        if(c == '0') { /* octal? */
194
 
                CHKiRet(ctokGetCharFromStream(pThis, &c));
195
 
                if(c == 'x') { /* nope, hex! */
196
 
                        CHKiRet(ctokGetCharFromStream(pThis, &c));
197
 
                        c = tolower(c);
198
 
                        iBase = 16;
199
 
                } else {
200
 
                        iBase = 8;
201
 
                }
202
 
        } else {
203
 
                iBase = 10;
204
 
        }
205
 
                
206
 
        n = 0;
207
 
        /* this loop is quite simple, a variable name is terminated by whitespace. */
208
 
        while(isdigit(c) || (c >= 'a' && c <= 'f')) {
209
 
                if(isdigit(c)) {
210
 
                        valC = c - '0';
211
 
                } else {
212
 
                        valC = c - 'a' + 10;
213
 
                }
214
 
                
215
 
                if(valC >= iBase) {
216
 
                        if(iBase == 8) {
217
 
                                ABORT_FINALIZE(RS_RET_INVALID_OCTAL_DIGIT);
218
 
                        } else {
219
 
                                ABORT_FINALIZE(RS_RET_INVALID_HEX_DIGIT);
220
 
                        }
221
 
                }
222
 
                /* we now have the next value and know it is right */
223
 
                n = n * iBase + valC;
224
 
                CHKiRet(ctokGetCharFromStream(pThis, &c));
225
 
                c = tolower(c);
226
 
        }
227
 
 
228
 
        /* we need to unget the character that made the loop terminate */
229
 
        CHKiRet(ctokUngetCharFromStream(pThis, c));
230
 
 
231
 
        CHKiRet(var.SetNumber(pToken->pVar, n));
232
 
 
233
 
finalize_it:
234
 
        RETiRet;
235
 
}
236
 
 
237
 
 
238
 
/* read in a variable
239
 
 * This covers both msgvar and sysvar from the ABNF.
240
 
 * rgerhards, 2008-02-19
241
 
 */
242
 
static rsRetVal
243
 
ctokGetVar(ctok_t *pThis, ctok_token_t *pToken)
244
 
{
245
 
        DEFiRet;
246
 
        uchar c;
247
 
        cstr_t *pstrVal;
248
 
 
249
 
        ISOBJ_TYPE_assert(pThis, ctok);
250
 
        ASSERT(pToken != NULL);
251
 
 
252
 
        CHKiRet(ctokGetCharFromStream(pThis, &c));
253
 
 
254
 
        if(c == '$') { /* second dollar, we have a system variable */
255
 
                pToken->tok = ctok_SYSVAR;
256
 
                CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */
257
 
        } else {
258
 
                pToken->tok = ctok_MSGVAR;
259
 
        }
260
 
 
261
 
        CHKiRet(rsCStrConstruct(&pstrVal));
262
 
        /* this loop is quite simple, a variable name is terminated by whitespace. */
263
 
        while(!isspace(c)) {
264
 
                CHKiRet(rsCStrAppendChar(pstrVal, tolower(c)));
265
 
                CHKiRet(ctokGetCharFromStream(pThis, &c));
266
 
        }
267
 
        CHKiRet(rsCStrFinish(pStrB));
268
 
 
269
 
        CHKiRet(var.SetString(pToken->pVar, pstrVal));
270
 
        pstrVal = NULL;
271
 
 
272
 
finalize_it:
273
 
        if(iRet != RS_RET_OK) {
274
 
                if(pstrVal != NULL) {
275
 
                        rsCStrDestruct(&pstrVal);
276
 
                }
277
 
        }
278
 
 
279
 
        RETiRet;
280
 
}
281
 
 
282
 
 
283
 
/* read in a simple string (simpstr in ABNF)
284
 
 * rgerhards, 2008-02-19
285
 
 */
286
 
static rsRetVal
287
 
ctokGetSimpStr(ctok_t *pThis, ctok_token_t *pToken)
288
 
{
289
 
        DEFiRet;
290
 
        uchar c;
291
 
        int bInEsc = 0;
292
 
        cstr_t *pstrVal;
293
 
 
294
 
        ISOBJ_TYPE_assert(pThis, ctok);
295
 
        ASSERT(pToken != NULL);
296
 
 
297
 
        pToken->tok = ctok_SIMPSTR;
298
 
 
299
 
        CHKiRet(rsCStrConstruct(&pstrVal));
300
 
        CHKiRet(ctokGetCharFromStream(pThis, &c));
301
 
        /* while we are in escape mode (had a backslash), no sequence
302
 
         * terminates the loop. If outside, it is terminated by a single quote.
303
 
         */
304
 
        while(bInEsc || c != '\'') {
305
 
                if(bInEsc) {
306
 
                        CHKiRet(rsCStrAppendChar(pstrVal, c));
307
 
                        bInEsc = 0;
308
 
                } else {
309
 
                        if(c == '\\') {
310
 
                                bInEsc = 1;
311
 
                        } else {
312
 
                                CHKiRet(rsCStrAppendChar(pstrVal, c));
313
 
                        }
314
 
                }
315
 
                CHKiRet(ctokGetCharFromStream(pThis, &c));
316
 
        }
317
 
        CHKiRet(rsCStrFinish(pStrB));
318
 
 
319
 
        CHKiRet(var.SetString(pToken->pVar, pstrVal));
320
 
        pstrVal = NULL;
321
 
 
322
 
finalize_it:
323
 
        if(iRet != RS_RET_OK) {
324
 
                if(pstrVal != NULL) {
325
 
                        rsCStrDestruct(&pstrVal);
326
 
                }
327
 
        }
328
 
 
329
 
        RETiRet;
330
 
}
331
 
 
332
 
 
333
 
/* Unget a token. The token ungotten will be returned the next time
334
 
 * ctokGetToken() is called. Only one token can be ungotten at a time.
335
 
 * If a second token is ungotten, the first is lost. This is considered
336
 
 * a programming error.
337
 
 * rgerhards, 2008-02-20
338
 
 */
339
 
static rsRetVal
340
 
ctokUngetToken(ctok_t *pThis, ctok_token_t *pToken)
341
 
{
342
 
        DEFiRet;
343
 
 
344
 
        ISOBJ_TYPE_assert(pThis, ctok);
345
 
        ASSERT(pToken != NULL);
346
 
        ASSERT(pThis->pUngotToken == NULL);
347
 
 
348
 
        pThis->pUngotToken = pToken;
349
 
 
350
 
        RETiRet;
351
 
}
352
 
 
353
 
 
354
 
/* skip an inine comment (just like a C-comment) 
355
 
 * rgerhards, 2008-02-20
356
 
 */
357
 
static rsRetVal
358
 
ctokSkipInlineComment(ctok_t *pThis)
359
 
{
360
 
        DEFiRet;
361
 
        uchar c;
362
 
        int bHadAsterisk = 0;
363
 
 
364
 
        ISOBJ_TYPE_assert(pThis, ctok);
365
 
 
366
 
        CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */
367
 
        while(!(bHadAsterisk && c == '/')) {
368
 
                bHadAsterisk = (c == '*') ? 1 : 0;
369
 
                CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read next */
370
 
        }
371
 
 
372
 
finalize_it:
373
 
        RETiRet;
374
 
}
375
 
 
376
 
 
377
 
 
378
 
/* Get the *next* token from the input stream. This parses the next token and
379
 
 * ignores any whitespace in between. End of stream is communicated via iRet.
380
 
 * The returned token must either be destructed by the caller OR being passed
381
 
 * back to ctokUngetToken().
382
 
 * rgerhards, 2008-02-19
383
 
 */
384
 
static rsRetVal
385
 
ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken)
386
 
{
387
 
        DEFiRet;
388
 
        ctok_token_t *pToken;
389
 
        uchar c;
390
 
        uchar szWord[128];
391
 
        int bRetry = 0; /* retry parse? Only needed for inline comments... */
392
 
 
393
 
        ISOBJ_TYPE_assert(pThis, ctok);
394
 
        ASSERT(ppToken != NULL);
395
 
 
396
 
        /* first check if we have an ungotten token and, if so, provide that
397
 
         * one back (without any parsing). -- rgerhards, 2008-02-20
398
 
         */
399
 
        if(pThis->pUngotToken != NULL) {
400
 
                *ppToken = pThis->pUngotToken;
401
 
                pThis->pUngotToken = NULL;
402
 
                FINALIZE;
403
 
        }
404
 
 
405
 
        /* setup the stage - create our token */
406
 
        CHKiRet(ctok_token.Construct(&pToken));
407
 
        CHKiRet(ctok_token.ConstructFinalize(pToken));
408
 
 
409
 
        /* find the next token. We may loop when we have inline comments */
410
 
        do {
411
 
                bRetry = 0;
412
 
                CHKiRet(ctokSkipWhitespaceFromStream(pThis));
413
 
                CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */
414
 
                switch(c) {
415
 
                        case '=': /* == */
416
 
                                CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */
417
 
                                pToken->tok = (c == '=')? ctok_CMP_EQ : ctok_INVALID;
418
 
                                break;
419
 
                        case '!': /* != */
420
 
                                CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */
421
 
                                pToken->tok = (c == '=')? ctok_CMP_NEQ : ctok_INVALID;
422
 
                                break;
423
 
                        case '<': /* <, <=, <> */
424
 
                                CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */
425
 
                                if(c == '=') {
426
 
                                        pToken->tok = ctok_CMP_LTEQ;
427
 
                                } else if(c == '>') {
428
 
                                        pToken->tok = ctok_CMP_NEQ;
429
 
                                } else {
430
 
                                        pToken->tok = ctok_CMP_LT;
431
 
                                }
432
 
                                break;
433
 
                        case '>': /* >, >= */
434
 
                                CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */
435
 
                                if(c == '=') {
436
 
                                        pToken->tok = ctok_CMP_GTEQ;
437
 
                                } else {
438
 
                                        pToken->tok = ctok_CMP_GT;
439
 
                                }
440
 
                                break;
441
 
                        case '+':
442
 
                                pToken->tok = ctok_PLUS;
443
 
                                break;
444
 
                        case '-':
445
 
                                pToken->tok = ctok_MINUS;
446
 
                                break;
447
 
                        case '*':
448
 
                                pToken->tok = ctok_TIMES;
449
 
                                break;
450
 
                        case '/': /* /, /.* ... *./ (comments, mungled here for obvious reasons...) */
451
 
                                CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */
452
 
                                if(c == '*') {
453
 
                                        /* we have a comment and need to skip it */
454
 
                                        ctokSkipInlineComment(pThis);
455
 
                                        bRetry = 1;
456
 
                                } else {
457
 
                                        CHKiRet(ctokUngetCharFromStream(pThis, c)); /* put back, not processed */
458
 
                                }
459
 
                                pToken->tok = ctok_DIV;
460
 
                                break;
461
 
                        case '%':
462
 
                                pToken->tok = ctok_MOD;
463
 
                                break;
464
 
                        case '(':
465
 
                                pToken->tok = ctok_LPAREN;
466
 
                                break;
467
 
                        case ')':
468
 
                                pToken->tok = ctok_RPAREN;
469
 
                                break;
470
 
                        case ',':
471
 
                                pToken->tok = ctok_COMMA;
472
 
                                break;
473
 
                        case '&':
474
 
                                pToken->tok = ctok_STRADD;
475
 
                                break;
476
 
                        case '$':
477
 
                                CHKiRet(ctokGetVar(pThis, pToken));
478
 
                                break;
479
 
                        case '\'': /* simple string, this is somewhat more elaborate */
480
 
                                CHKiRet(ctokGetSimpStr(pThis, pToken));
481
 
                                break;
482
 
                        case '"':
483
 
                                /* TODO: template string parser */
484
 
                                ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED);
485
 
                                break;
486
 
                        default:
487
 
                                CHKiRet(ctokUngetCharFromStream(pThis, c)); /* push back, we need it in any case */
488
 
                                if(isdigit(c)) {
489
 
                                        CHKiRet(ctokGetNumber(pThis, pToken));
490
 
                                } else { /* now we check if we have a multi-char sequence */
491
 
                                        CHKiRet(ctokGetWordFromStream(pThis, szWord, sizeof(szWord)/sizeof(uchar)));
492
 
                                        if(!strcasecmp((char*)szWord, "and")) {
493
 
                                                pToken->tok = ctok_AND;
494
 
                                        } else if(!strcasecmp((char*)szWord, "or")) {
495
 
                                                pToken->tok = ctok_OR;
496
 
                                        } else if(!strcasecmp((char*)szWord, "not")) {
497
 
                                                pToken->tok = ctok_NOT;
498
 
                                        } else if(!strcasecmp((char*)szWord, "contains")) {
499
 
                                                pToken->tok = ctok_CMP_CONTAINS;
500
 
                                        } else if(!strcasecmp((char*)szWord, "contains_i")) {
501
 
                                                pToken->tok = ctok_CMP_CONTAINSI;
502
 
                                        } else if(!strcasecmp((char*)szWord, "startswith")) {
503
 
                                                pToken->tok = ctok_CMP_STARTSWITH;
504
 
                                        } else if(!strcasecmp((char*)szWord, "startswith_i")) {
505
 
                                                pToken->tok = ctok_CMP_STARTSWITHI;
506
 
                                        } else if(!strcasecmp((char*)szWord, "then")) {
507
 
                                                pToken->tok = ctok_THEN;
508
 
                                        } else {
509
 
                                                /* finally, we check if it is a function */
510
 
                                                CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */
511
 
                                                if(c == '(') {
512
 
                                                        /* push c back, higher level parser needs it */
513
 
                                                        CHKiRet(ctokUngetCharFromStream(pThis, c));
514
 
                                                        pToken->tok = ctok_FUNCTION;
515
 
                                                        // TODO: fill function name
516
 
                                                } else { /* give up... */
517
 
                                                        pToken->tok = ctok_INVALID;
518
 
                                                }
519
 
                                        }
520
 
                                }
521
 
                                break;
522
 
                }
523
 
        } while(bRetry); /* warning: do ... while()! */
524
 
 
525
 
        *ppToken = pToken;
526
 
        dbgoprint((obj_t*) pToken, "token: %d\n", pToken->tok);
527
 
 
528
 
finalize_it:
529
 
        if(iRet != RS_RET_OK) {
530
 
                if(pToken != NULL)
531
 
                        ctok_token.Destruct(&pToken);
532
 
        }
533
 
 
534
 
        RETiRet;
535
 
}
536
 
 
537
 
 
538
 
/* property set methods */
539
 
/* simple ones first */
540
 
DEFpropSetMeth(ctok, pp, uchar*)
541
 
 
542
 
/* return the current position of pp - most important as currently we do only
543
 
 * partial parsing, so the rest must know where to start from...
544
 
 * rgerhards, 2008-02-19
545
 
 */
546
 
static rsRetVal
547
 
ctokGetpp(ctok_t *pThis, uchar **pp)
548
 
{
549
 
        DEFiRet;
550
 
        ASSERT(pp != NULL);
551
 
        *pp = pThis->pp;
552
 
        RETiRet;
553
 
}
554
 
 
555
 
 
556
 
/* queryInterface function
557
 
 * rgerhards, 2008-02-21
558
 
 */
559
 
BEGINobjQueryInterface(ctok)
560
 
CODESTARTobjQueryInterface(ctok)
561
 
        if(pIf->ifVersion != ctokCURR_IF_VERSION) { /* check for current version, increment on each change */
562
 
                ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
563
 
        }
564
 
 
565
 
        /* ok, we have the right interface, so let's fill it
566
 
         * Please note that we may also do some backwards-compatibility
567
 
         * work here (if we can support an older interface version - that,
568
 
         * of course, also affects the "if" above).
569
 
         */
570
 
        //xxxpIf->oID = OBJctok;
571
 
 
572
 
        pIf->Construct = ctokConstruct;
573
 
        pIf->ConstructFinalize = ctokConstructFinalize;
574
 
        pIf->Destruct = ctokDestruct;
575
 
        pIf->Getpp = ctokGetpp;
576
 
        pIf->GetToken = ctokGetToken;
577
 
        pIf->UngetToken = ctokUngetToken;
578
 
        pIf->Setpp = ctokSetpp;
579
 
finalize_it:
580
 
ENDobjQueryInterface(ctok)
581
 
 
582
 
 
583
 
 
584
 
BEGINObjClassInit(ctok, 1, OBJ_IS_CORE_MODULE) /* class, version */
585
 
        /* request objects we use */
586
 
        CHKiRet(objUse(ctok_token, CORE_COMPONENT));
587
 
        CHKiRet(objUse(var, CORE_COMPONENT));
588
 
 
589
 
        OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctokConstructFinalize);
590
 
ENDObjClassInit(ctok)
591
 
 
592
 
/* vi:set ai:
593
 
 */