1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019, Joyent, Inc.
14  */
15 
16 #ifndef _STRVIEW_H
17 #define	_STRVIEW_H
18 
19 #include <inttypes.h>
20 
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24 
25 /*
26  * strview_t's represent a read-only subset of a string.  It is somewhat
27  * similar to the concept of ranges found in other languages in that one can
28  * create a strview_t, and then create a smaller range for iteration.
29  *
30  * sv_first is the address of the first location (and is advanced as values
31  * are consumed) in the string.
32  *
33  * sv_last is the address one byte after the last valid value of the subset.
34  * Basically, the length of the range is equal to 'sv_last - sv_first'.  For
35  * example, in the string 'abcdef' to create a view 'bcd', *sv_first would
36  * equal 'b' and *sv_last would equal 'e'.
37  *
38  * sv_rem is the number of bytes remaining in the range.
39  *
40  * A strview_t maintains references to the underlying string, so the lifetime
41  * of a strview_t should be equal to or less than the underlying string (i.e.
42  * it doesn't copy the data from the underlying string, but maintains pointers
43  * to the original data).
44  *
45  * While the underlying string does not need to be NUL-terminated, NUL is still
46  * used as a sentinel value in some instances (e.g. sv_peek()), and should not
47  * be contained within the defined range.
48  *
49  * As hinted above, the functions currently do not deal with multi-byte
50  * characters, i.e. each character is assumed to be a single byte.  The
51  * current consumers do not need to handle multi-byte characters (UTF-8
52  * or otherwise), so this is sufficient at the current time.
53  */
54 typedef struct strview {
55 	const char *sv_first;
56 	const char *sv_last;
57 	size_t sv_rem;
58 } strview_t;
59 
60 /*
61  * SV_PRINT() is used for printing strview_t values during debugging, e.g.
62  * `DEMDEBUG("%*.s", SV_PRINT(sv));`
63  */
64 #define	SV_PRINT(_sv)	(int)(_sv)->sv_rem, (_sv)->sv_first
65 
66 /*
67  * Initialize a strview_t from an already initialized strview_t -- the state of
68  * the source strview_t is duplicated in the newly initialized strview_t.
69  */
70 void sv_init_sv(strview_t *, const strview_t *);
71 
72 /*
73  * Initialize a strview_t as a subset of an already initialized strview_t.
74  * The size of the subset (size_t) must be <= sv_remaining(src).
75  */
76 void sv_init_sv_range(strview_t *, const strview_t *, size_t);
77 
78 /*
79  * Initialize a strview_t from a string.  The two const char * pointers are the
80  * sv_first and sv_last values to use (see above).  If the source string is
81  * NUL-terminated, one can optionally pass NULL for the second parameter in
82  * which case, the entire NUL-terminated string (starting at sv_first) is
83  * treated as a strview_t.
84  */
85 void sv_init_str(strview_t *, const char *, const char *);
86 
87 /*
88  * Return the number of bytes remaining to consume in the strview_t
89  */
90 size_t sv_remaining(const strview_t *);
91 
92 /*
93  * Return the char at the given position in the strview_t (without advancing
94  * the position).  Position values >=0 are relative to the current position
95  * of the strview_t (e.g. '0' will return the next character, '1' will return
96  * the character after that), while negative position values are relative to
97  * the end of the strview_t (e.g. '-1' will return the last character, '-2'
98  * will return the second to last character).
99  *
100  * If the position value is out of range, '\0' is returned.
101  */
102 char sv_peek(const strview_t *, ssize_t);
103 
104 /*
105  * Return the next character and advance the strview_t position.  If no more
106  * characters are available, '\0' is returned.
107  */
108 char sv_consume_c(strview_t *);
109 
110 /*
111  * Advance the position of the strview_t by the given number of bytes.  The
112  * amount must be <= the number of bytes remaining in the strview_t.
113  */
114 void sv_consume_n(strview_t *, size_t);
115 
116 /*
117  * Advance the strview_t position if the bytes of the strview starting at the
118  * current position match the given NUL-terminated string.  The length of the
119  * NUL-terminated string must be <= the number of bytes remaining in the
120  * strview_t.
121  *
122  * If there is a match, the position of the strview_t is advanced by the
123  * length of the NUL-terminated comparison string, and B_TRUE is returned. If
124  * there is no match, the position is not advanced and B_FALSE is returned.
125  */
126 boolean_t sv_consume_if(strview_t *, const char *);
127 
128 /*
129  * Advance the position of the strview_t if the next char in the strview_t
130  * is equal to the given char.  If there is a match, the strview_t position
131  * is advanced one byte and B_TRUE is returned.  If they do not match, B_FALSE
132  * is returned and the position is not advanced.
133  */
134 boolean_t sv_consume_if_c(strview_t *, char);
135 
136 #ifdef __cplusplus
137 }
138 #endif
139 
140 #endif /* _STRVIEW_H */
141