Annotation of previous/src/debug/evaluate.c, revision 1.1.1.1

1.1       root        1: /*
                      2:   Hatari - calculate.c
                      3: 
                      4:   Copyright (C) 1994, 2009 by Eero Tamminen
                      5: 
                      6:   This file is distributed under the GNU Public License, version 2 or at
                      7:   your option any later version. Read the file gpl.txt for details.
                      8: 
                      9:   calculate.c - parse numbers, number ranges and expressions. Supports
                     10:   most unary and binary operations, parenthesis and order of precedence.
                     11:   Originally based on code from my Clac calculator MiNT filter version.
                     12: */
                     13: const char Eval_fileid[] = "Hatari calculate.c : " __DATE__ " " __TIME__;
                     14: 
                     15: #include <ctype.h>
                     16: #include <limits.h>
                     17: #include <errno.h>
                     18: #include <stdio.h>
                     19: #include <stdlib.h>
                     20: #include <stdbool.h>
                     21: #include <SDL_types.h>
                     22: #include "configuration.h"
                     23: #include "debugcpu.h"
                     24: #include "evaluate.h"
                     25: #include "main.h"
                     26: #include "m68000.h"
                     27: #include "symbols.h"
                     28: 
                     29: /* define which character indicates which type of number on expression  */
                     30: #define PREFIX_BIN '%'                            /* binary decimal       */
                     31: #define PREFIX_DEC '#'                             /* normal decimal       */
                     32: #define PREFIX_HEX '$'                             /* hexadecimal          */
                     33: 
                     34: /* define error codes                                                   */
                     35: #define CLAC_EXP_ERR "No expression given"
                     36: #define CLAC_GEN_ERR "Syntax error"
                     37: #define CLAC_PAR_ERR "Mismatched parenthesis"
                     38: #define CLAC_DEF_ERR "Undefined result (1/0)"
                     39: #define CLAC_STK_ERR "Operation/value stack full"
                     40: #define CLAC_OVF_ERR "Overflow"
                     41: #define CLAC_OVR_ERR "Mode overflow"
                     42: #define CLAC_PRG_ERR "Internal program error"
                     43: 
                     44: /* define internal allocation sizes (should be enough ;-)              */
                     45: #define PARDEPTH_MAX   64              /* max. parenth. nesting depth  */
                     46: #define OSTACK_MAX     128             /* size of the operator stack   */
                     47: #define VSTACK_MAX     128             /* size of the value stack      */
                     48: 
                     49: /* operation with lowest precedence, used to finish calculations */
                     50: #define LOWEST_PREDECENCE '|'
                     51: 
                     52: /* globals + function identifier stack(s)                              */
                     53: static struct {
                     54:        const char *error;              /* global error code            */
                     55:        bool valid;                     /* value validation             */
                     56: } id = {0, 0};
                     57: 
                     58: /* parenthesis and function stacks                                     */
                     59: static struct {
                     60:        int idx;                        /* parenthesis level            */
                     61:        int max;                        /* maximum idx                  */
                     62:        int opx[PARDEPTH_MAX + 1];      /* current op index for par     */
                     63:        int vax[PARDEPTH_MAX + 1];      /* current val index for par    */
                     64: } par = {0, PARDEPTH_MAX, {0}, {0}};
                     65: 
                     66: static struct {                                        /* operator stack       */
                     67:        int idx;
                     68:        int max;
                     69:        char buf[OSTACK_MAX + 1];
                     70: } op = {0, OSTACK_MAX, ""};
                     71: 
                     72: static struct value_stk {                      /* value stack  */
                     73:        int idx;
                     74:        int max;
                     75:        long long buf[VSTACK_MAX + 1];
                     76: } val = {0, VSTACK_MAX, {0}};
                     77: 
                     78: /* -------------------------------------------------------------------- */
                     79: /* macros                                                              */
                     80: 
                     81: /* increment stack index and put value on stack (ie. PUSH)             */
                     82: #define PUSH(stk,val) \
                     83:        if((stk).idx < (stk).max) {             \
                     84:                (stk).idx += 1;                 \
                     85:                (stk).buf[(stk).idx] = (val);   \
                     86:        } else {                                \
                     87:                id.error = CLAC_STK_ERR;        \
                     88:        }
                     89: 
                     90: /* -------------------------------------------------------------------- */
                     91: /* declare subfunctions                                                        */
                     92: 
                     93: /* parse in-between operations */
                     94: static void operation(long long value, char op);
                     95: /* parse unary operators       */
                     96: static void unary (char op);
                     97: /* apply a prefix to a value */
                     98: static void apply_prefix(void);
                     99: /* juggle stacks, if possible  */
                    100: static void eval_stack(void);
                    101: /* operator -> operator level  */
                    102: static int get_level(int stk_offset);
                    103: /* evaluate operation          */
                    104: static long long apply_op(char op, long long x, long long y);
                    105: 
                    106: /* increase parenthesis level  */
                    107: static void open_bracket(void);
                    108: /* decrease parenthesis level  */
                    109: static long long close_bracket(long long x);
                    110: 
                    111: 
                    112: /**
                    113:  * Parse & set an (unsigned) number, assuming it's in the configured
                    114:  * default number base unless it has a prefix:
                    115:  * - '$' / '0x' / '0h' => hexadecimal
                    116:  * - '#' / '0d' => normal decimal
                    117:  * - '%' / '0b' => binary decimal
                    118:  * - '0o' => octal decimal
                    119:  * Return how many characters were parsed or zero for error.
                    120:  */
                    121: static int getNumber(const char *str, Uint32 *number, int *nbase)
                    122: {
                    123:        char *end;
                    124:        const char const *start = str;
                    125:        int base = ConfigureParams.Debugger.nNumberBase;
                    126:        unsigned long int value;
                    127: 
                    128:        if (!str[0]) {
                    129:                fprintf(stderr, "Value missing!\n");
                    130:                return 0;
                    131:        }
                    132:        
                    133:        /* determine correct number base */
                    134:        if (str[0] == '0') {
                    135: 
                    136:                /* 0x & 0h = hex, 0d = dec, 0o = oct, 0b = bin ? */
                    137:                switch(str[1]) {
                    138:                case 'b':
                    139:                        base = 2;
                    140:                        break;
                    141:                case 'o':
                    142:                        base = 8;
                    143:                        break;
                    144:                case 'd':
                    145:                        base = 10;
                    146:                        break;
                    147:                case 'h':
                    148:                case 'x':
                    149:                        base = 16;
                    150:                        break;
                    151:                default:
                    152:                        str -= 2;
                    153:                }
                    154:                str += 2;
                    155:        }
                    156:        else if (!isxdigit(str[0])) {
                    157: 
                    158:                /* doesn't start with (hex) number -> is it prefix? */
                    159:                switch (*str++) {
                    160:                case PREFIX_BIN:
                    161:                        base = 2;
                    162:                        break;
                    163:                case PREFIX_DEC:
                    164:                        base = 10;
                    165:                        break;
                    166:                case PREFIX_HEX:
                    167:                        base = 16;
                    168:                        break;
                    169:                default:
                    170:                        fprintf(stderr, "Unrecognized number prefix in '%s'!\n", start);
                    171:                        return 0;
                    172:                }
                    173:        }
                    174:        *nbase = base;
                    175: 
                    176:        /* parse number */
                    177:        errno = 0;
                    178:        value = strtoul(str, &end, base);
                    179:        if (errno == ERANGE && value == LONG_MAX) {
                    180:                fprintf(stderr, "Overflow with value '%s'!\n", start);
                    181:                return 0;
                    182:        }
                    183:        if ((errno != 0 && value == 0) || end == str) {
                    184:                fprintf(stderr, "Invalid value '%s'!\n", start);
                    185:                return 0;
                    186:        }
                    187:        *number = value;
                    188:        return end - start;
                    189: }
                    190: 
                    191: 
                    192: /**
                    193:  * Parse unsigned register/symbol/number value and set it to "number".
                    194:  * Return how many characters were parsed or zero for error.
                    195:  */
                    196: static int getValue(const char *str, Uint32 *number, bool bForDsp)
                    197: {
                    198:        char name[64];
                    199:        const char *end;
                    200:        Uint32 mask, *addr;
                    201:        int len, dummy;
                    202: 
                    203:        for (end = str; *end == '_' || isalnum(*end); end++);
                    204:        
                    205:        len = end-str;
                    206:        if (len >= (int)sizeof(name)) {
                    207:                fprintf(stderr, "ERROR: symbol name at '%s' too long (%d chars)\n", str, len);
                    208:                return 0;
                    209:        }
                    210:        memcpy(name, str, len);
                    211:        name[len] = '\0';
                    212: 
                    213:        if (bForDsp) {
                    214:                if (Symbols_GetDspAddress(SYMTYPE_ALL, name, number)) {
                    215:                        return len;
                    216:                }
                    217:        } else {
                    218:                /* a special case CPU register? */
                    219:                if (strcasecmp(name, "PC") == 0) {
                    220:                        *number = M68000_GetPC();
                    221:                        return len;
                    222:                }
                    223:                if (strcasecmp(name, "SR") == 0) {
                    224:                        *number = M68000_GetSR();
                    225:                        return len;
                    226:                }
                    227:                /* a normal CPU  register or symbol? */
                    228:                if (DebugCpu_GetRegisterAddress(name, &addr)) {
                    229:                        *number = *addr;
                    230:                        return len;
                    231:                }
                    232:                if (Symbols_GetCpuAddress(SYMTYPE_ALL, name, number)) {
                    233:                        return len;
                    234:                }
                    235:        }
                    236: 
                    237:        /* none of above, assume it's a number */
                    238:        return getNumber(str, number, &dummy);
                    239: }
                    240: 
                    241: 
                    242: /**
                    243:  * Parse & set an (unsigned) number, assume it's in the configured
                    244:  * default number base unless it has a suitable prefix.
                    245:  * Return true for success and false for failure.
                    246:  */
                    247: bool Eval_Number(const char *str, Uint32 *number)
                    248: {
                    249:        int offset, base = 0;
                    250:        
                    251:        offset = getNumber(str, number, &base);
                    252:        if (!offset) {
                    253:                return false;
                    254:        }
                    255:        if (str[offset]) {
                    256:                const char *basestr;
                    257: 
                    258:                switch (base) {
                    259:                case 2:
                    260:                        basestr = "binary";
                    261:                        break;
                    262:                case 8:
                    263:                        basestr = "octal";
                    264:                        break;
                    265:                case 10:
                    266:                        basestr = "decimal";
                    267:                        break;
                    268:                case 16:
                    269:                        basestr = "hexadecimal";
                    270:                        break;
                    271:                default:
                    272:                        basestr = "unknown";
                    273:        }
                    274:                fprintf(stderr, "Extra characters in %s based number '%s'!\n",
                    275:                        basestr, str);
                    276:                return false;
                    277:        }
                    278:        return true;
                    279: }
                    280: 
                    281: 
                    282: /**
                    283:  * Get a an adress range, eg. "$fa0000-$fa0100"
                    284:  * returns:
                    285:  *  0 if OK,
                    286:  * -1 if not syntaxically a range,
                    287:  * -2 if values are invalid,
                    288:  * -3 if syntaxically range, but not value-wise.
                    289:  */
                    290: static int getRange(char *str1, Uint32 *lower, Uint32 *upper)
                    291: {
                    292:        bool fDash = false;
                    293:        char *str2 = str1;
                    294:        int ret = 0;
                    295: 
                    296:        while (*str2) {
                    297:                if (*str2 == '-') {
                    298:                        *str2++ = '\0';
                    299:                        fDash = true;
                    300:                        break;
                    301:                }
                    302:                str2++;
                    303:        }
                    304:        if (!fDash)
                    305:                return -1;
                    306: 
                    307:        if (!Eval_Number(str1, lower))
                    308:                ret = -2;
                    309:        else if (!Eval_Number(str2, upper))
                    310:                ret = -2;
                    311:        else if (*lower > *upper)
                    312:                ret = -3;
                    313:        *--str2 = '-';
                    314:        return ret;
                    315: }
                    316: 
                    317: 
                    318: /**
                    319:  * Parse an adress range, eg. "$fa0000[-$fa0100]" + show appropriate warnings
                    320:  * returns:
                    321:  * -1 if invalid address or range,
                    322:  *  0 if single address,
                    323:  * +1 if a range.
                    324:  */
                    325: int Eval_Range(char *str, Uint32 *lower, Uint32 *upper)
                    326: {
                    327:        switch (getRange(str, lower, upper)) {
                    328:        case 0:
                    329:                return 1;
                    330:        case -1:
                    331:                /* single address, not a range */
                    332:                if (!Eval_Number(str, lower))
                    333:                        return -1;
                    334:                return 0;
                    335:        case -2:
                    336:                fprintf(stderr,"Invalid address values in '%s'!\n", str);
                    337:                return -1;
                    338:        case -3:
                    339:                fprintf(stderr,"Invalid range ($%x > $%x)!\n", *lower, *upper);
                    340:                return -1;
                    341:        }
                    342:        fprintf(stderr, "INTERNAL ERROR: Unknown getRange() return value.\n");
                    343:        return -1;
                    344: }
                    345: 
                    346: 
                    347: /**
                    348:  * Evaluate expression. bForDsp determines which registers and symbols
                    349:  * are interpreted. Sets given value and parsing offset.
                    350:  * Return error string or NULL for success.
                    351:  */
                    352: const char* Eval_Expression(const char *in, Uint32 *out, int *erroff, bool bForDsp)
                    353: {
                    354:        /* in    : expression to evaluate                               */
                    355:        /* out   : final parsed value                                   */
                    356:        /* value : current parsed value                                 */
                    357:        /* mark  : current character in expression                      */
                    358:        /* valid : expression validation flag, set when number parsed   */
                    359:        /* end   : 'expression end' flag                                */
                    360:        /* offset: character offset in expression                       */
                    361: 
                    362:        long long value;
                    363:        int offset = 0;
                    364:        char mark;
                    365:        
                    366:        /* Uses global variables:       */
                    367: 
                    368:        par.idx = 0;                    /* parenthesis stack pointer    */
                    369:        par.opx[0] = par.vax[0] = 0;    /* additional stack pointers    */
                    370:        op.idx = val.idx = -1;
                    371: 
                    372:        id.error = NULL;
                    373:        id.valid = false;               /* value validation             */
                    374:        value = 0;
                    375: 
                    376:        /* parsing loop, repeated until expression ends */
                    377:        do {
                    378:                mark = in[offset];
                    379:                switch(mark) {
                    380:                case '\0':
                    381:                        break;
                    382:                case ' ':
                    383:                case '\t':
                    384:                        offset ++;              /* jump over white space */
                    385:                        break;
                    386:                case '~':                       /* prefixes */
                    387:                        unary(mark);
                    388:                        offset ++;
                    389:                        break;
                    390:                case '>':                       /* operators  */
                    391:                case '<':
                    392:                        offset ++;
                    393:                        /* check that it's '>>' or '<<' */
                    394:                        if (in[offset] != mark)
                    395:                        {
                    396:                                id.error = CLAC_GEN_ERR;
                    397:                                break;
                    398:                        }
                    399:                        operation (value, mark);
                    400:                        offset ++;
                    401:                        break;
                    402:                case '|':
                    403:                case '&':
                    404:                case '^':
                    405:                case '+':
                    406:                case '-':
                    407:                case '*':
                    408:                case '/':
                    409:                        operation (value, mark);
                    410:                        offset ++;
                    411:                        break;
                    412:                case '(':
                    413:                        open_bracket ();
                    414:                        offset ++;
                    415:                        break;
                    416:                case ')':
                    417:                        value = close_bracket (value);
                    418:                        offset ++;
                    419:                        break;
                    420:                default:
                    421:                        /* register/symbol/number value needed? */
                    422:                        if (id.valid == false) {
                    423:                                Uint32 tmp;
                    424:                                int consumed;
                    425:                                consumed = getValue(&(in[offset]), &tmp, bForDsp);
                    426:                                /* number parsed? */
                    427:                                if (consumed) {
                    428:                                        offset += consumed;
                    429:                                        id.valid = true;
                    430:                                        value = tmp;
                    431:                                        break;
                    432:                                }
                    433:                        }
                    434:                        id.error = CLAC_GEN_ERR;
                    435:                }
                    436: 
                    437:        /* until exit or error message                                  */
                    438:        } while(mark && !id.error);
                    439: 
                    440:         /* result of evaluation                                        */
                    441:         if (val.idx >= 0)
                    442:                *out = val.buf[val.idx];
                    443: 
                    444:        /* something to return?                                         */
                    445:        if (!id.error) {
                    446:                if (id.valid) {
                    447: 
                    448:                        /* evaluate rest of the expression              */
                    449:                        operation (value, LOWEST_PREDECENCE);
                    450:                        if (par.idx)                    /* mismatched   */
                    451:                                id.error = CLAC_PAR_ERR;
                    452:                        else                            /* result out   */
                    453:                                *out = val.buf[val.idx];
                    454: 
                    455:                } else {
                    456:                        if ((val.idx < 0) && (op.idx < 0)) {
                    457:                                id.error = CLAC_EXP_ERR;
                    458:                        } else                  /* trailing operators   */
                    459:                                id.error = CLAC_GEN_ERR;
                    460:                }
                    461:        }
                    462: 
                    463:        *erroff = offset;
                    464:        if (id.error) {
                    465:                *out = 0;
                    466:                return id.error;
                    467:        }
                    468:        return NULL;
                    469: }
                    470: 
                    471: 
                    472: /* ==================================================================== */
                    473: /*                     expression evaluation                           */
                    474: /* ==================================================================== */
                    475: 
                    476: static void operation (long long value, char oper)
                    477: {
                    478:        /* uses globals par[], id.error[], op[], val[]
                    479:         * operation executed if the next one is on same or lower level
                    480:         */
                    481:        /* something to calc? */
                    482:        if(id.valid == true) {
                    483:                
                    484:                /* add new items to stack */
                    485:                PUSH(op, oper);
                    486:                PUSH(val, value);
                    487:                
                    488:                /* more than 1 operator  */
                    489:                if(op.idx > par.opx[par.idx]) {
                    490: 
                    491:                        /* but only one value */
                    492:                        if(val.idx == par.vax[par.idx]) {
                    493:                                apply_prefix();
                    494:                        } else {
                    495:                                /* evaluate all possible operations */
                    496:                                eval_stack();
                    497:                        }
                    498:                }
                    499:                /* next a number needed */
                    500:                id.valid = false;
                    501:        } else {
                    502:                /* pre- or post-operators instead of in-betweens? */
                    503:                unary(oper);
                    504:        }
                    505: }
                    506: 
                    507: /**
                    508:  * handle unary operators
                    509:  */
                    510: static void unary (char oper)
                    511: {
                    512:        /* check pre-value operators
                    513:         * have to be parenthesised
                    514:         */
                    515:        if(id.valid == false && op.idx < par.opx[par.idx])
                    516:        {
                    517:                switch(oper) {
                    518:                case '+':               /* not needed */
                    519:                        break;
                    520:                case '-':
                    521:                case '~':
                    522:                        PUSH(op, oper);
                    523:                        break;
                    524:                default:
                    525:                        id.error = CLAC_GEN_ERR;
                    526:                }
                    527:        }
                    528:        else
                    529:                id.error = CLAC_GEN_ERR;
                    530: }
                    531: 
                    532: /**
                    533:  * apply a prefix to the current value
                    534:  */
                    535: static void apply_prefix(void)
                    536: {
                    537:        long long value = val.buf[val.idx];
                    538: 
                    539:        op.idx--;
                    540:        switch(op.buf[op.idx]) {
                    541:        case '-':
                    542:                value = (-value);
                    543:                break;
                    544:        case '~':
                    545:                value = (~value);
                    546:                break;
                    547:        default:
                    548:                id.error = CLAC_PRG_ERR;
                    549:        }
                    550:        val.buf[val.idx] = value;
                    551:        op.buf[op.idx] = op.buf[op.idx + 1];
                    552: }
                    553: 
                    554: /* -------------------------------------------------------------------- */
                    555: /**
                    556:  * evaluate operators if precedence allows it
                    557:  */
                    558: /* evaluate all possible (according to order of precedence) operators  */
                    559: static void eval_stack (void)
                    560: {
                    561:        /* uses globals par[], op[], val[]      */
                    562: 
                    563:        /* # of operators >= 2 and prev. op-level >= current op-level ? */
                    564:        while ((op.idx > par.opx[par.idx]) && get_level (-1) >= get_level (0)) {
                    565: 
                    566:                /* shorten value stacks by one  */
                    567:                /* + calculate resulting value  */
                    568:                op.idx -= 1;
                    569:                val.idx -= 1;
                    570:                val.buf[val.idx] = apply_op(op.buf[op.idx],
                    571:                        val.buf[val.idx], val.buf[val.idx + 1]);
                    572: 
                    573:                /* pull the just used operator out of the stack         */
                    574:                op.buf[op.idx] = op.buf[op.idx + 1];
                    575:        }
                    576: }
                    577: 
                    578: /* -------------------------------------------------------------------- */
                    579: /**
                    580:  * return the precedence level of a given operator
                    581:  */
                    582: static int get_level (int offset)
                    583: {
                    584:        /* used globals par[], op[]
                    585:         * returns operator level of: operator[stack idx + offset]
                    586:         */
                    587:        switch(op.buf[op.idx + offset]) {
                    588:        case '|':      /* binary operations  */
                    589:        case '&':
                    590:        case '^':
                    591:                return 0;
                    592:                
                    593:        case '>':      /* bit shifting    */
                    594:        case '<':
                    595:                return 1;
                    596:                
                    597:        case '+':
                    598:        case '-':
                    599:                return 2;
                    600:                
                    601:        case '*':
                    602:        case '/':
                    603:                return 3;
                    604:                
                    605:        default:
                    606:                id.error = CLAC_PRG_ERR;
                    607:        }
                    608:        return 6;
                    609: }
                    610: 
                    611: /* -------------------------------------------------------------------- */
                    612: /**
                    613:  * apply operator to given values, return the result
                    614:  */
                    615: static long long apply_op (char opcode, long long value1, long long value2)
                    616: {
                    617:        /* uses global id.error[]               */
                    618:        /* returns the result of operation      */
                    619: 
                    620:        switch (opcode) {
                    621:         case '|':
                    622:                value1 |= value2;
                    623:                break;
                    624:         case '&':
                    625:                value1 &= value2;
                    626:                break;
                    627:         case '^':
                    628:                value1 ^= value2;
                    629:                break;
                    630:         case '>':
                    631:                value1 >>= value2;
                    632:         case '<':
                    633:                value1 <<= value2;
                    634:                break;
                    635:        case '+':
                    636:                value1 += value2;
                    637:                break;
                    638:        case '-':
                    639:                value1 -= value2;
                    640:                break;
                    641:        case '*':
                    642:                value1 *= value2;
                    643:                break;
                    644:        case '/':
                    645:                /* don't divide by zero */
                    646:                if (value2)
                    647:                        value1 /= value2;
                    648:                else
                    649:                        id.error = CLAC_DEF_ERR;
                    650:                break;
                    651:         default:
                    652:                id.error = CLAC_PRG_ERR;
                    653:        }
                    654:        return value1;                          /* return result        */
                    655: }
                    656: 
                    657: 
                    658: /* ==================================================================== */
                    659: /*                     parenthesis and help                            */
                    660: /* ==================================================================== */
                    661: 
                    662: /**
                    663:  * open prenthesis, push values & operators to stack
                    664:  */
                    665: static void open_bracket (void)
                    666: {
                    667:        if (id.valid == false) {                /* preceded by operator */
                    668:                if (par.idx < PARDEPTH_MAX) {   /* not nested too deep  */
                    669:                        par.idx ++;
                    670:                        par.opx[par.idx] = op.idx + 1;
                    671:                        par.vax[par.idx] = val.idx + 1;
                    672:                } else
                    673:                        id.error = CLAC_STK_ERR;
                    674:        } else
                    675:                id.error = CLAC_GEN_ERR;
                    676: }
                    677: 
                    678: /* -------------------------------------------------------------------- */
                    679: /**
                    680:  * close prenthesis, and evaluate / pop stacks
                    681:  */
                    682: /* last parsed value, last param. flag, trigonometric mode     */
                    683: static long long close_bracket (long long value)
                    684: {
                    685:        /* returns the value of the parenthesised expression    */
                    686: 
                    687:        if (id.valid) {                 /* preceded by an operator      */
                    688:                if (par.idx > 0) {      /* prenthesis has a pair        */
                    689:                        /* calculate the value of parenthesised exp.    */
                    690:                        operation (value, LOWEST_PREDECENCE);
                    691:                        value = val.buf[val.idx];
                    692:                        op.idx = par.opx[par.idx] - 1;  /* restore prev */
                    693:                        val.idx = par.vax[par.idx] - 1;
                    694:                        par.idx --;
                    695: 
                    696:                        /* next operator */
                    697:                        id.valid = true;
                    698:                } else
                    699:                        id.error = CLAC_PAR_ERR;
                    700:        } else
                    701:                id.error = CLAC_GEN_ERR;
                    702: 
                    703:        return value;
                    704: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.