-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathiter.c
142 lines (130 loc) · 3.31 KB
/
iter.c
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
#include "iter.h"
#include <string.h>
#include <ctype.h>
#include "ctest.h"
/* # DESCRIPTION
*
* `peek` is a utility method that allows for
* a value on iteration to be 'peeked' - i.e. the value is
* evaluated without moving the iterator forward. It does
* so via pointer arithmetic without updating the current
* position of the pointer.
*
* This is useful in scenarios where you may want to check the
* next value of an iteration without 'consuming' it
*
* # RETURN
* A `reference` to the next character in the iteration.
*
*
* # EXAMPLE
* ```c
* int c;
* char *s = "abcd";
*
* // while the string is not at null termination '\0'
* // move forward.
* // if the next value is 'c' then break.
* while((c = *s++)) if(peek(s) == 'c') break;
*
* // because we peeked, the iteration will have stopped
* // at 'b' rather than 'c'.
* assert_eq_int('b', *s);
* ```
*/
__attribute__((always_inline))
int peek(char *s)
{
return *(s + 1);
}
/* # DESCRIPTION
*
* `next` is a utility method that moves a pointer
* forward by one.
*
* This is used for when you want to consume an element and
* move forward.
*
* # RETURN
*
* The next character in iteration, consumed.
*
* # EXAMPLE
* ```c
* int c;
* char *s = "abcd";
*
* // while the string is not at null termination '\0'
* // move forward.
* // if the current value is 'c' then break.
* while((c = next(&s))) if(c == 'c') break;
* assert_eq_int('c', c);
* ```
*/
__attribute__((always_inline))
int next(char **s)
{
(*s)++;
return **s;
}
/* # DESCRIPTION
*
* `skip_until_eq` moves the pointer of the 'haystack'
* forward until it matches a given `needle`.
*
* # RETURN
*
* 0 if successful, an error code otherwise. The haystack pointer is updated to point at the needle if found. Reset to start if not.
*
* # ERRORS
*
* - ENULLHAYSTACK - indicates the haystack was null or empty
* - EEMPTYNEEDLE - indicates that the needle is empty or null
* - ENOMATCHFOUND - indicates that not match for that needle was found in the haystack.
*/
int __skip_until_eq(char **haystack, char* needle)
{
char *start;
size_t needlelen, haystacklen;
start = *haystack;
if(!haystack || !(*haystack)) return ENULLHAYSTACK;
if(!needle) return EEMPTYNEEDLE;
needlelen = strlen(needle), haystacklen = strlen(*haystack);
while((*(*haystack)) && haystacklen >= needlelen) {
if(strncmp((*haystack), needle, needlelen) == 0) return 0;
else ((*haystack)++,haystacklen--);
}
*haystack = start;
return ENOMATCHFOUND;
}
__TEST(test_skip_until_eq_no_match,
char p[] = "<html><meta text='123'/><meta text='233232'/><body></body></html>";
char *ptr = p;
char *needle = "<p>";
int res = __skip_until_eq(&ptr, needle);
assert_eq_int(ENOMATCHFOUND, res);
assert_eq_str(p,ptr);
)
__TEST(test_skip_until_eq,
char p[] = "<html><meta text='123'/><meta text='233232'/><body></body></html>";
char *ptr = p;
char *needle = "<body>";
int res = __skip_until_eq(&ptr, needle);
assert_eq_int(0, res);
assert_eq_str("<body></body></html>",ptr);
)
__TEST(test_next,
int c;
char *w = "abcd";
while((c = next(&w)))
if(c == 'c') break;
assert_eq_int('c', *w);
)
__TEST(test_peek,
int c;
char *w = "abcd";
while((c = next(&w)))
if(peek(w) == 'c') break;
assert_eq_int('b',*w);
)
__TEST_MOD(iter,4,test_next,test_skip_until_eq_no_match,test_peek,test_skip_until_eq)