File: rxclass.c

package info (click to toggle)
ruby-oj 3.16.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,852 kB
  • sloc: ansic: 19,402; ruby: 11,451; makefile: 17
file content (144 lines) | stat: -rw-r--r-- 3,503 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (c) 2017 Peter Ohler. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license details.

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#if !IS_WINDOWS
#include <regex.h>
#endif

#include "mem.h"
#include "rxclass.h"

typedef struct _rxC {
    struct _rxC *next;
    VALUE        rrx;
#if !IS_WINDOWS
    regex_t rx;
#endif
    VALUE clas;
    char  src[256];
} *RxC;

void oj_rxclass_init(RxClass rc) {
    *rc->err = '\0';
    rc->head = NULL;
    rc->tail = NULL;
}

void oj_rxclass_cleanup(RxClass rc) {
    RxC rxc;

    while (NULL != (rxc = rc->head)) {
        rc->head = rc->head->next;
#if !IS_WINDOWS
        if (Qnil == rxc->rrx) {
            regfree(&rxc->rx);
        }
        OJ_R_FREE(rxc);
#endif
    }
}

void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas) {
    RxC rxc = OJ_R_ALLOC_N(struct _rxC, 1);

    memset(rxc, 0, sizeof(struct _rxC));
    rxc->rrx  = rx;
    rxc->clas = clas;
    if (NULL == rc->tail) {
        rc->head = rxc;
    } else {
        rc->tail->next = rxc;
    }
    rc->tail = rxc;
}

// Attempt to compile the expression. If it fails populate the error code..
int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
    RxC rxc;
#if !IS_WINDOWS
    int err;
    int flags = 0;
#endif
    if (sizeof(rxc->src) <= strlen(expr)) {
        snprintf(rc->err,
                 sizeof(rc->err),
                 "expressions must be less than %lu characters",
                 (unsigned long)sizeof(rxc->src));
        return EINVAL;
    }
    rxc       = OJ_R_ALLOC_N(struct _rxC, 1);
    rxc->next = 0;
    rxc->clas = clas;

#if IS_WINDOWS
    rxc->rrx = rb_funcall(rb_cRegexp, rb_intern("new"), 1, rb_str_new2(expr));
#else
    rxc->rrx = Qnil;
    if (0 != (err = regcomp(&rxc->rx, expr, flags))) {
        regerror(err, &rxc->rx, rc->err, sizeof(rc->err));
        OJ_FREE(rxc);
        return err;
    }
#endif
    if (NULL == rc->tail) {
        rc->head = rxc;
    } else {
        rc->tail->next = rxc;
    }
    rc->tail = rxc;

    return 0;
}

VALUE
oj_rxclass_match(RxClass rc, const char *str, int len) {
    RxC  rxc;
    char buf[4096];

    for (rxc = rc->head; NULL != rxc; rxc = rxc->next) {
        if (Qnil != rxc->rrx) {
            // Must use a valiabel for this to work.
            volatile VALUE rstr = rb_str_new(str, len);

            // if (Qtrue == rb_funcall(rxc->rrx, rb_intern("match?"), 1, rstr)) {
            if (Qnil != rb_funcall(rxc->rrx, rb_intern("match"), 1, rstr)) {
                return rxc->clas;
            }
        } else if (len < (int)sizeof(buf)) {
#if !IS_WINDOWS
            // string is not \0 terminated so copy and attempt a match
            memcpy(buf, str, len);
            buf[len] = '\0';
            if (0 == regexec(&rxc->rx, buf, 0, NULL, 0)) {  // match
                return rxc->clas;
            }
#endif
        } else {
            // TBD allocate a larger buffer and attempt
        }
    }
    return Qnil;
}

void oj_rxclass_copy(RxClass src, RxClass dest) {
    dest->head = NULL;
    dest->tail = NULL;
    if (NULL != src->head) {
        RxC rxc;

        for (rxc = src->head; NULL != rxc; rxc = rxc->next) {
            if (Qnil != rxc->rrx) {
                oj_rxclass_rappend(dest, rxc->rrx, rxc->clas);
            } else {
#if !IS_WINDOWS
                oj_rxclass_append(dest, rxc->src, rxc->clas);
#endif
            }
        }
    }
}