VirtualBox

Changeset 3192 in kBuild for trunk/src/kmk/kmkbuiltin/expr.c


Ignore:
Timestamp:
Mar 26, 2018 8:25:56 PM (7 years ago)
Author:
bird
Message:

kmkbuiltin: funnel output thru output.c (usually via err.c).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/kmkbuiltin/expr.c

    r3140 r3192  
    2222#endif
    2323#include "err.h"
    24 #include "getopt.h"
    2524#include "kmkbuiltin.h"
    2625
    27 static struct val       *make_int(int);
    28 static struct val       *make_str(char *);
    29 static void              free_value(struct val *);
     26typedef struct EXPRINSTANCE *PEXPRINSTANCE;
     27
     28static struct val       *make_int(PEXPRINSTANCE, int);
     29static struct val       *make_str(PEXPRINSTANCE, char *);
     30static void              free_value(PEXPRINSTANCE, struct val *);
    3031static int               is_integer(struct val *, int *);
    31 static int               to_integer(struct val *);
    32 static void              to_string(struct val *);
    33 static int               is_zero_or_null(struct val *);
    34 static void              nexttoken(int);
    35 static struct val       *eval6(void);
    36 static struct val       *eval5(void);
    37 static struct val       *eval4(void);
    38 static struct val       *eval3(void);
    39 static struct val       *eval2(void);
    40 static struct val       *eval1(void);
    41 static struct val       *eval0(void);
     32static int               to_integer(PEXPRINSTANCE, struct val *);
     33static void              to_string(PEXPRINSTANCE, struct val *);
     34static int               is_zero_or_null(PEXPRINSTANCE, struct val *);
     35static void              nexttoken(PEXPRINSTANCE, int);
     36static struct val       *eval6(PEXPRINSTANCE);
     37static struct val       *eval5(PEXPRINSTANCE);
     38static struct val       *eval4(PEXPRINSTANCE);
     39static struct val       *eval3(PEXPRINSTANCE);
     40static struct val       *eval2(PEXPRINSTANCE);
     41static struct val       *eval1(PEXPRINSTANCE);
     42static struct val       *eval0(PEXPRINSTANCE);
    4243
    4344enum token {
     
    5859};
    5960
    60 static enum token       token;
    61 static struct val     *tokval;
    62 static char           **av;
    63 static jmp_buf          g_expr_jmp;
    64 static void           **recorded_allocations;
    65 static int              num_recorded_allocations;
    66 
    67 
    68 static void expr_mem_record_alloc(void *ptr)
    69 {
    70         if (!(num_recorded_allocations & 31)) {
    71                 void *newtab = realloc(recorded_allocations, (num_recorded_allocations + 33) * sizeof(void *));
     61typedef struct EXPRINSTANCE {
     62    PKMKBUILTINCTX  pCtx;
     63    enum token      token;
     64    struct val     *tokval;
     65    char          **av;
     66    jmp_buf         g_expr_jmp;
     67    void          **recorded_allocations;
     68    int             num_recorded_allocations;
     69} EXPRINSTANCE;
     70
     71
     72static void expr_mem_record_alloc(PEXPRINSTANCE pThis, void *ptr)
     73{
     74        if (!(pThis->num_recorded_allocations & 31)) {
     75                void *newtab = realloc(pThis->recorded_allocations, (pThis->num_recorded_allocations + 33) * sizeof(void *));
    7276                if (!newtab)
    73                         longjmp(g_expr_jmp, err(3, NULL));
    74                 recorded_allocations = (void **)newtab;
    75         }
    76         recorded_allocations[num_recorded_allocations++] = ptr;
    77 }
    78 
    79 
    80 static void expr_mem_record_free(void *ptr)
    81 {
    82         int i = num_recorded_allocations;
     77                        longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL));
     78                pThis->recorded_allocations = (void **)newtab;
     79        }
     80        pThis->recorded_allocations[pThis->num_recorded_allocations++] = ptr;
     81}
     82
     83
     84static void expr_mem_record_free(PEXPRINSTANCE pThis, void *ptr)
     85{
     86        int i = pThis->num_recorded_allocations;
    8387        while (i-- > 0)
    84                 if (recorded_allocations[i] == ptr) {
    85                         num_recorded_allocations--;
    86                         recorded_allocations[i] = recorded_allocations[num_recorded_allocations];
     88                if (pThis->recorded_allocations[i] == ptr) {
     89                        pThis->num_recorded_allocations--;
     90                        pThis->recorded_allocations[i] = pThis->recorded_allocations[pThis->num_recorded_allocations];
    8791                        return;
    8892                }
     
    9094}
    9195
    92 static void expr_mem_init(void)
    93 {
    94         num_recorded_allocations = 0;
    95         recorded_allocations = NULL;
    96 }
    97 
    98 static void expr_mem_cleanup(void)
    99 {
    100         if (recorded_allocations) {
    101                 while (num_recorded_allocations-- > 0)
    102                         free(recorded_allocations[num_recorded_allocations]);
    103                 free(recorded_allocations);
    104                 recorded_allocations = NULL;
    105         }
    106 }
    107 
    108 
    109 static struct val *
    110 make_int(int i)
     96static void expr_mem_init(PEXPRINSTANCE pThis)
     97{
     98        pThis->num_recorded_allocations = 0;
     99        pThis->recorded_allocations = NULL;
     100}
     101
     102static void expr_mem_cleanup(PEXPRINSTANCE pThis)
     103{
     104        if (pThis->recorded_allocations) {
     105                while (pThis->num_recorded_allocations-- > 0)
     106                        free(pThis->recorded_allocations[pThis->num_recorded_allocations]);
     107                free(pThis->recorded_allocations);
     108                pThis->recorded_allocations = NULL;
     109        }
     110}
     111
     112
     113static struct val *
     114make_int(PEXPRINSTANCE pThis, int i)
    111115{
    112116        struct val     *vp;
     
    114118        vp = (struct val *) malloc(sizeof(*vp));
    115119        if (vp == NULL)
    116                 longjmp(g_expr_jmp, err(3, NULL));
    117         expr_mem_record_alloc(vp);
     120                longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL));
     121        expr_mem_record_alloc(pThis, vp);
    118122        vp->type = integer;
    119123        vp->u.i = i;
     
    123127
    124128static struct val *
    125 make_str(char *s)
     129make_str(PEXPRINSTANCE pThis, char *s)
    126130{
    127131        struct val     *vp;
     
    129133        vp = (struct val *) malloc(sizeof(*vp));
    130134        if (vp == NULL || ((vp->u.s = strdup(s)) == NULL))
    131                 longjmp(g_expr_jmp, err(3, NULL));
    132         expr_mem_record_alloc(vp->u.s);
    133         expr_mem_record_alloc(vp);
     135                longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL));
     136        expr_mem_record_alloc(pThis, vp->u.s);
     137        expr_mem_record_alloc(pThis, vp);
    134138        vp->type = string;
    135139        return vp;
     
    138142
    139143static void
    140 free_value(struct val *vp)
     144free_value(PEXPRINSTANCE pThis, struct val *vp)
    141145{
    142146        if (vp->type == string) {
    143                 expr_mem_record_free(vp->u.s);
     147                expr_mem_record_free(pThis, vp->u.s);
    144148                free(vp->u.s);
    145149        }
    146150        free(vp);
    147         expr_mem_record_free(vp);
     151        expr_mem_record_free(pThis, vp);
    148152}
    149153
     
    193197/* coerce to vp to an integer */
    194198static int
    195 to_integer(struct val *vp)
     199to_integer(PEXPRINSTANCE pThis, struct val *vp)
    196200{
    197201        int             r;
     
    201205
    202206        if (is_integer(vp, &r)) {
    203                 expr_mem_record_free(vp->u.s);
     207                expr_mem_record_free(pThis, vp->u.s);
    204208                free(vp->u.s);
    205209                vp->u.i = r;
     
    214218/* coerce to vp to an string */
    215219static void
    216 to_string(struct val *vp)
     220to_string(PEXPRINSTANCE pThis, struct val *vp)
    217221{
    218222        char           *tmp;
     
    222226
    223227        if (asprintf(&tmp, "%d", vp->u.i) == -1)
    224                 longjmp(g_expr_jmp, err(3, NULL));
    225         expr_mem_record_alloc(tmp);
     228                longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL));
     229        expr_mem_record_alloc(pThis, tmp);
    226230
    227231        vp->type = string;
     
    230234
    231235static int
    232 is_zero_or_null(struct val *vp)
     236is_zero_or_null(PEXPRINSTANCE pThis, struct val *vp)
    233237{
    234238        if (vp->type == integer) {
    235239                return (vp->u.i == 0);
    236240        } else {
    237                 return (*vp->u.s == 0 || (to_integer(vp) && vp->u.i == 0));
     241                return (*vp->u.s == 0 || (to_integer(pThis, vp) && vp->u.i == 0));
    238242        }
    239243        /* NOTREACHED */
     
    241245
    242246static void
    243 nexttoken(int pat)
     247nexttoken(PEXPRINSTANCE pThis, int pat)
    244248{
    245249        char           *p;
    246250
    247         if ((p = *av) == NULL) {
    248                 token = EOI;
     251        if ((p = *pThis->av) == NULL) {
     252                pThis->token = EOI;
    249253                return;
    250254        }
    251         av++;
     255        pThis->av++;
    252256
    253257
     
    258262
    259263                        if ((i = strchr(x, *p)) != NULL) {
    260                                 token = i - x;
     264                                pThis->token = i - x;
    261265                                return;
    262266                        }
     
    264268                        switch (*p) {
    265269                        case '<':
    266                                 token = LE;
     270                                pThis->token = LE;
    267271                                return;
    268272                        case '>':
    269                                 token = GE;
     273                                pThis->token = GE;
    270274                                return;
    271275                        case '!':
    272                                 token = NE;
     276                                pThis->token = NE;
    273277                                return;
    274278                        }
    275279                }
    276280        }
    277         tokval = make_str(p);
    278         token = OPERAND;
     281        pThis->tokval = make_str(pThis, p);
     282        pThis->token = OPERAND;
    279283        return;
    280284}
     
    287291#endif
    288292static void
    289 error(void)
    290 {
    291         longjmp(g_expr_jmp, errx(2, "syntax error"));
     293error(PEXPRINSTANCE pThis)
     294{
     295        longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "syntax error"));
    292296        /* NOTREACHED */
    293297}
    294298
    295299static struct val *
    296 eval6(void)
     300eval6(PEXPRINSTANCE pThis)
    297301{
    298302        struct val     *v;
    299303
    300         if (token == OPERAND) {
    301                 nexttoken(0);
    302                 return tokval;
    303 
    304         } else if (token == RP) {
    305                 nexttoken(0);
    306                 v = eval0();
    307 
    308                 if (token != LP) {
    309                         error();
     304        if (pThis->token == OPERAND) {
     305                nexttoken(pThis, 0);
     306                return pThis->tokval;
     307
     308        } else if (pThis->token == RP) {
     309                nexttoken(pThis, 0);
     310                v = eval0(pThis);
     311
     312                if (pThis->token != LP) {
     313                        error(pThis);
    310314                        /* NOTREACHED */
    311315                }
    312                 nexttoken(0);
     316                nexttoken(pThis, 0);
    313317                return v;
    314318        } else {
    315                 error();
     319                error(pThis);
    316320        }
    317321        /* NOTREACHED */
     
    320324/* Parse and evaluate match (regex) expressions */
    321325static struct val *
    322 eval5(void)
     326eval5(PEXPRINSTANCE pThis)
    323327{
    324328#ifdef KMK_WITH_REGEX
     
    332336        struct val     *l;
    333337
    334         l = eval6();
    335         while (token == MATCH) {
     338        l = eval6(pThis);
     339        while (pThis->token == MATCH) {
    336340#ifdef KMK_WITH_REGEX
    337                 nexttoken(1);
    338                 r = eval6();
     341                nexttoken(pThis, 1);
     342                r = eval6(pThis);
    339343
    340344                /* coerce to both arguments to strings */
    341                 to_string(l);
    342                 to_string(r);
     345                to_string(pThis, l);
     346                to_string(pThis, r);
    343347
    344348                /* compile regular expression */
    345349                if ((eval = regcomp(&rp, r->u.s, 0)) != 0) {
    346350                        regerror(eval, &rp, errbuf, sizeof(errbuf));
    347                         longjmp(g_expr_jmp, errx(2, "%s", errbuf));
     351                        longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "%s", errbuf));
    348352                }
    349353
     
    353357                        if (rm[1].rm_so >= 0) {
    354358                                *(l->u.s + rm[1].rm_eo) = '\0';
    355                                 v = make_str(l->u.s + rm[1].rm_so);
     359                                v = make_str(pThis, l->u.s + rm[1].rm_so);
    356360
    357361                        } else {
    358                                 v = make_int((int)(rm[0].rm_eo - rm[0].rm_so));
     362                                v = make_int(pThis, (int)(rm[0].rm_eo - rm[0].rm_so));
    359363                        }
    360364                } else {
    361365                        if (rp.re_nsub == 0) {
    362                                 v = make_int(0);
     366                                v = make_int(pThis, 0);
    363367                        } else {
    364                                 v = make_str("");
     368                                v = make_str(pThis, "");
    365369                        }
    366370                }
    367371
    368372                /* free arguments and pattern buffer */
    369                 free_value(l);
    370                 free_value(r);
     373                free_value(pThis, l);
     374                free_value(pThis, r);
    371375                regfree(&rp);
    372376
    373377                l = v;
    374378#else
    375                 longjmp(g_expr_jmp, errx(2, "regex not supported, sorry."));
     379                longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "regex not supported, sorry."));
    376380#endif
    377381        }
     
    382386/* Parse and evaluate multiplication and division expressions */
    383387static struct val *
    384 eval4(void)
     388eval4(PEXPRINSTANCE pThis)
    385389{
    386390        struct val     *l, *r;
    387391        enum token      op;
    388392
    389         l = eval5();
    390         while ((op = token) == MUL || op == DIV || op == MOD) {
    391                 nexttoken(0);
    392                 r = eval5();
    393 
    394                 if (!to_integer(l) || !to_integer(r)) {
    395                         longjmp(g_expr_jmp, errx(2, "non-numeric argument"));
     393        l = eval5(pThis);
     394        while ((op = pThis->token) == MUL || op == DIV || op == MOD) {
     395                nexttoken(pThis, 0);
     396                r = eval5(pThis);
     397
     398                if (!to_integer(pThis, l) || !to_integer(pThis, r)) {
     399                        longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "non-numeric argument"));
    396400                }
    397401
     
    400404                } else {
    401405                        if (r->u.i == 0) {
    402                                 longjmp(g_expr_jmp, errx(2, "division by zero"));
     406                                longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "division by zero"));
    403407                        }
    404408                        if (op == DIV) {
     
    409413                }
    410414
    411                 free_value(r);
     415                free_value(pThis, r);
    412416        }
    413417
     
    417421/* Parse and evaluate addition and subtraction expressions */
    418422static struct val *
    419 eval3(void)
     423eval3(PEXPRINSTANCE pThis)
    420424{
    421425        struct val     *l, *r;
    422426        enum token      op;
    423427
    424         l = eval4();
    425         while ((op = token) == ADD || op == SUB) {
    426                 nexttoken(0);
    427                 r = eval4();
    428 
    429                 if (!to_integer(l) || !to_integer(r)) {
    430                         longjmp(g_expr_jmp, errx(2, "non-numeric argument"));
     428        l = eval4(pThis);
     429        while ((op = pThis->token) == ADD || op == SUB) {
     430                nexttoken(pThis, 0);
     431                r = eval4(pThis);
     432
     433                if (!to_integer(pThis, l) || !to_integer(pThis, r)) {
     434                        longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "non-numeric argument"));
    431435                }
    432436
     
    437441                }
    438442
    439                 free_value(r);
     443                free_value(pThis, r);
    440444        }
    441445
     
    445449/* Parse and evaluate comparison expressions */
    446450static struct val *
    447 eval2(void)
     451eval2(PEXPRINSTANCE pThis)
    448452{
    449453        struct val     *l, *r;
     
    451455        int             v = 0, li, ri;
    452456
    453         l = eval3();
    454         while ((op = token) == EQ || op == NE || op == LT || op == GT ||
     457        l = eval3(pThis);
     458        while ((op = pThis->token) == EQ || op == NE || op == LT || op == GT ||
    455459            op == LE || op == GE) {
    456                 nexttoken(0);
    457                 r = eval3();
     460                nexttoken(pThis, 0);
     461                r = eval3(pThis);
    458462
    459463                if (is_integer(l, &li) && is_integer(r, &ri)) {
     
    481485                        }
    482486                } else {
    483                         to_string(l);
    484                         to_string(r);
     487                        to_string(pThis, l);
     488                        to_string(pThis, r);
    485489
    486490                        switch (op) {
     
    508512                }
    509513
    510                 free_value(l);
    511                 free_value(r);
    512                 l = make_int(v);
     514                free_value(pThis, l);
     515                free_value(pThis, r);
     516                l = make_int(pThis, v);
    513517        }
    514518
     
    518522/* Parse and evaluate & expressions */
    519523static struct val *
    520 eval1(void)
     524eval1(PEXPRINSTANCE pThis)
    521525{
    522526        struct val     *l, *r;
    523527
    524         l = eval2();
    525         while (token == AND) {
    526                 nexttoken(0);
    527                 r = eval2();
    528 
    529                 if (is_zero_or_null(l) || is_zero_or_null(r)) {
    530                         free_value(l);
    531                         free_value(r);
    532                         l = make_int(0);
     528        l = eval2(pThis);
     529        while (pThis->token == AND) {
     530                nexttoken(pThis, 0);
     531                r = eval2(pThis);
     532
     533                if (is_zero_or_null(pThis, l) || is_zero_or_null(pThis, r)) {
     534                        free_value(pThis, l);
     535                        free_value(pThis, r);
     536                        l = make_int(pThis, 0);
    533537                } else {
    534                         free_value(r);
     538                        free_value(pThis, r);
    535539                }
    536540        }
     
    541545/* Parse and evaluate | expressions */
    542546static struct val *
    543 eval0(void)
     547eval0(PEXPRINSTANCE pThis)
    544548{
    545549        struct val     *l, *r;
    546550
    547         l = eval1();
    548         while (token == OR) {
    549                 nexttoken(0);
    550                 r = eval1();
    551 
    552                 if (is_zero_or_null(l)) {
    553                         free_value(l);
     551        l = eval1(pThis);
     552        while (pThis->token == OR) {
     553                nexttoken(pThis, 0);
     554                r = eval1(pThis);
     555
     556                if (is_zero_or_null(pThis, l)) {
     557                        free_value(pThis, l);
    554558                        l = r;
    555559                } else {
    556                         free_value(r);
     560                        free_value(pThis, r);
    557561                }
    558562        }
     
    563567
    564568int
    565 kmk_builtin_expr(int argc, char *argv[], char **envp)
    566 {
    567         struct val     *vp;
     569kmk_builtin_expr(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
     570{
     571        EXPRINSTANCE This;
     572        struct val *vp;
    568573        int rval;
    569 
    570         /* re-init globals */
    571         token = 0;
    572         tokval = 0;
    573         av = 0;
    574         expr_mem_init();
    575 
    576 #ifdef kmk_builtin_expr /* kmk already does this. */
    577         (void) setlocale(LC_ALL, "");
    578 #endif
    579574
    580575        if (argc > 1 && !strcmp(argv[1], "--"))
    581576                argv++;
    582577
    583         av = argv + 1;
    584 
    585         rval = setjmp(g_expr_jmp);
     578        /* Init globals */
     579        This.pCtx = pCtx;
     580        This.token = 0;
     581        This.tokval = 0;
     582        This.av = argv + 1;
     583        expr_mem_init(&This);
     584
     585        rval = setjmp(This.g_expr_jmp);
    586586        if (!rval) {
    587                 nexttoken(0);
    588                 vp = eval0();
    589 
    590                 if (token != EOI) {
    591                         error();
     587                nexttoken(&This, 0);
     588                vp = eval0(&This);
     589
     590                if (This.token != EOI) {
     591                        error(&This);
    592592                        /* NOTREACHED */
    593593                }
    594594
    595595                if (vp->type == integer)
    596                         printf("%d\n", vp->u.i);
     596                        kmk_builtin_ctx_printf(pCtx, 0, "%d\n", vp->u.i);
    597597                else
    598                         printf("%s\n", vp->u.s);
    599 
    600                 rval = is_zero_or_null(vp);
     598                        kmk_builtin_ctx_printf(pCtx, 0, "%s\n", vp->u.s);
     599
     600                rval = is_zero_or_null(&This, vp);
    601601        }
    602602        /* else: longjmp */
    603603
    604604        /* cleanup */
    605         expr_mem_cleanup();
     605        expr_mem_cleanup(&This);
    606606        return rval;
    607607}
     608
     609#ifdef KMK_BUILTIN_STANDALONE
     610int main(int argc, char **argv, char **envp)
     611{
     612        KMKBUILTINCTX Ctx = { "kmk_expr", NULL };
     613        (void) setlocale(LC_ALL, "");
     614        return kmk_builtin_expr(argc, argv, envp, &Ctx);
     615}
     616#endif
     617
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette