1 /*
2  * Copyright 2008-2014 Arsen Chaloyan
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Id: apt_text_stream.h 2136 2014-07-04 06:33:36Z achaloyan@gmail.com $
17  */
18 
19 #ifndef APT_TEXT_STREAM_H
20 #define APT_TEXT_STREAM_H
21 
22 /**
23  * @file apt_text_stream.h
24  * @brief Text Stream Parse/Generate Routine
25  */
26 
27 #include "apt_string_table.h"
28 #include "apt_pair.h"
29 
30 APT_BEGIN_EXTERN_C
31 
32 /** Space */
33 #define APT_TOKEN_SP 0x20
34 /** Horizontal tab */
35 #define APT_TOKEN_HTAB 0x09
36 /** Carrige return */
37 #define APT_TOKEN_CR 0x0D
38 /** Line feed */
39 #define APT_TOKEN_LF 0x0A
40 
41 /** Text stream declaration */
42 typedef struct apt_text_stream_t apt_text_stream_t;
43 
44 /** Text stream is used for message parsing and generation */
45 struct apt_text_stream_t {
46 	/** Text stream */
47 	apt_str_t   text;
48 
49 	/** Current position in the stream */
50 	char       *pos;
51 	/** End of stream pointer */
52 	const char *end;
53 	/** Is end of stream reached */
54 	apt_bool_t  is_eos;
55 };
56 
57 
58 /**
59  * Read entire line of the text stream.
60  * @param stream the text stream to navigate on
61  * @param line the read line to return
62  * @return TRUE if the line is successfully read, otherwise FALSE
63  * @remark To be used to navigate through the lines of the text stream (message).
64  */
65 APT_DECLARE(apt_bool_t) apt_text_line_read(apt_text_stream_t *stream, apt_str_t *line);
66 
67 /**
68  * Read header field (name-value pair) of the text stream by scanning entire line.
69  * @param stream the text stream to navigate
70  * @param pair the read pair to return
71  * @return TRUE if the header is successfully read, otherwise FALSE
72  * @remark To be used to navigate through the lines and read header fields
73  * (name:value pairs) of the text stream (message).
74  */
75 APT_DECLARE(apt_bool_t) apt_text_header_read(apt_text_stream_t *stream, apt_pair_t *pair);
76 
77 /**
78  * Read the field terminated with specified separator.
79  * @param stream the text stream to navigate
80  * @param separator the field separator
81  * @param skip_spaces whether to skip spaces or not
82  * @param field the read field to return
83  * @return TRUE if the read field isn't empty, otherwise FALSE
84  * @remark To be used to navigate through the fields of the text stream (message).
85  */
86 APT_DECLARE(apt_bool_t) apt_text_field_read(apt_text_stream_t *stream, char separator, apt_bool_t skip_spaces, apt_str_t *field);
87 
88 /** Generate name-value pair line */
89 APT_DECLARE(apt_bool_t) apt_text_name_value_insert(apt_text_stream_t *stream, const apt_str_t *name, const apt_str_t *value);
90 
91 /** Generate only the name ("name:") of the header field */
92 APT_DECLARE(apt_bool_t) apt_text_header_name_insert(apt_text_stream_t *stream, const apt_str_t *name);
93 
94 /** Parse array of name-value pairs */
95 APT_DECLARE(apt_bool_t) apt_pair_array_parse(apt_pair_arr_t *arr, const apt_str_t *value, apr_pool_t *pool);
96 /** Generate array of name-value pairs */
97 APT_DECLARE(apt_bool_t) apt_pair_array_generate(const apt_pair_arr_t *arr, apt_str_t *str, apr_pool_t *pool);
98 
99 
100 /** Parse boolean-value */
101 APT_DECLARE(apt_bool_t) apt_boolean_value_parse(const apt_str_t *str, apt_bool_t *value);
102 /** Generate apr_size_t value from pool (buffer is allocated from pool) */
103 APT_DECLARE(apt_bool_t) apt_boolean_value_generate(apt_bool_t value, apt_str_t *str, apr_pool_t *pool);
104 
105 /** Parse apr_size_t value */
106 APT_DECLARE(apr_size_t) apt_size_value_parse(const apt_str_t *str);
107 /** Generate apr_size_t value from pool (buffer is allocated from pool) */
108 APT_DECLARE(apt_bool_t) apt_size_value_generate(apr_size_t value, apt_str_t *str, apr_pool_t *pool);
109 
110 /** Insert apr_size_t value */
111 APT_DECLARE(apt_bool_t) apt_text_size_value_insert(apt_text_stream_t *stream, apr_size_t value);
112 
113 /** Parse float value */
114 APT_DECLARE(float) apt_float_value_parse(const apt_str_t *str);
115 /** Generate float value (buffer is allocated from pool) */
116 APT_DECLARE(apt_bool_t) apt_float_value_generate(float value, apt_str_t *str, apr_pool_t *pool);
117 
118 /** Insert float value */
119 APT_DECLARE(apt_bool_t) apt_text_float_value_insert(apt_text_stream_t *stream, float value);
120 /** Insert string value */
121 APT_DECLARE(apt_bool_t) apt_text_string_insert(apt_text_stream_t *stream, const apt_str_t *str);
122 
123 /** Reset navigation related data of the text stream */
apt_text_stream_reset(apt_text_stream_t * stream)124 static APR_INLINE void apt_text_stream_reset(apt_text_stream_t *stream)
125 {
126 	stream->pos = stream->text.buf;
127 	stream->end = stream->text.buf + stream->text.length;
128 	stream->is_eos = FALSE;
129 }
130 
131 /** Initialize text stream */
apt_text_stream_init(apt_text_stream_t * stream,char * buffer,apr_size_t size)132 static APR_INLINE void apt_text_stream_init(apt_text_stream_t *stream, char *buffer, apr_size_t size)
133 {
134 	stream->text.buf = buffer;
135 	stream->text.length = size;
136 	apt_text_stream_reset(stream);
137 }
138 
139 /** Insert end of the line symbol(s) */
apt_text_eol_insert(apt_text_stream_t * stream)140 static APR_INLINE apt_bool_t apt_text_eol_insert(apt_text_stream_t *stream)
141 {
142 	if(stream->pos + 2 < stream->end) {
143 		*stream->pos++ = APT_TOKEN_CR;
144 		*stream->pos++ = APT_TOKEN_LF;
145 		return TRUE;
146 	}
147 	return FALSE;
148 }
149 
150 /** Insert character */
apt_text_char_insert(apt_text_stream_t * stream,char ch)151 static APR_INLINE apt_bool_t apt_text_char_insert(apt_text_stream_t *stream, char ch)
152 {
153 	if(stream->pos + 1 < stream->end) {
154 		*stream->pos++ = ch;
155 		return TRUE;
156 	}
157 	return FALSE;
158 }
159 
160 /** Insert space */
apt_text_space_insert(apt_text_stream_t * stream)161 static APR_INLINE apt_bool_t apt_text_space_insert(apt_text_stream_t *stream)
162 {
163 	return apt_text_char_insert(stream,APT_TOKEN_SP);
164 }
165 
166 /** Insert space */
apt_text_htab_insert(apt_text_stream_t * stream)167 static APR_INLINE apt_bool_t apt_text_htab_insert(apt_text_stream_t *stream)
168 {
169 	return apt_text_char_insert(stream,APT_TOKEN_HTAB);
170 }
171 
172 /** Check whether specified character is a white space (WSP = SP / HTAB) */
apt_text_is_wsp(char ch)173 static APR_INLINE apt_bool_t apt_text_is_wsp(char ch)
174 {
175 	return (ch == APT_TOKEN_SP || ch == APT_TOKEN_HTAB) ? TRUE : FALSE;
176 }
177 
178 /** Skip sequence of spaces */
apt_text_spaces_skip(apt_text_stream_t * stream)179 static APR_INLINE void apt_text_spaces_skip(apt_text_stream_t *stream)
180 {
181 	while(stream->pos < stream->end && *stream->pos == APT_TOKEN_SP)
182 		stream->pos++;
183 }
184 
185 /** Skip sequence of white spaces (WSP = SP / HTAB) */
apt_text_white_spaces_skip(apt_text_stream_t * stream)186 static APR_INLINE void apt_text_white_spaces_skip(apt_text_stream_t *stream)
187 {
188 	while(stream->pos < stream->end && apt_text_is_wsp(*stream->pos) == TRUE)
189 		stream->pos++;
190 }
191 
192 /** Skip specified character */
apt_text_char_skip(apt_text_stream_t * stream,char ch)193 static APR_INLINE void apt_text_char_skip(apt_text_stream_t *stream, char ch)
194 {
195 	if(stream->pos < stream->end && *stream->pos == ch) stream->pos++;
196 }
197 
198 /** Skip sequence of specified characters */
apt_text_chars_skip(apt_text_stream_t * stream,char ch)199 static APR_INLINE void apt_text_chars_skip(apt_text_stream_t *stream, char ch)
200 {
201 	while(stream->pos < stream->end && *stream->pos == ch) stream->pos++;
202 }
203 
204 /** Skip to specified character */
apt_text_skip_to_char(apt_text_stream_t * stream,char ch)205 static APR_INLINE void apt_text_skip_to_char(apt_text_stream_t *stream, char ch)
206 {
207 	while(stream->pos < stream->end && *stream->pos != ch) stream->pos++;
208 }
209 
210 /** Check whether end of stream is reached */
apt_text_is_eos(const apt_text_stream_t * stream)211 static APR_INLINE apt_bool_t apt_text_is_eos(const apt_text_stream_t *stream)
212 {
213 	return (stream->pos >= stream->end || stream->is_eos == TRUE) ? TRUE : FALSE;
214 }
215 
216 /** Scroll text stream */
217 APT_DECLARE(apt_bool_t) apt_text_stream_scroll(apt_text_stream_t *stream);
218 
219 /** Parse id at resource string */
220 APT_DECLARE(apt_bool_t) apt_id_resource_parse(const apt_str_t *str, char separator, apt_str_t *id, apt_str_t *resource, apr_pool_t *pool);
221 /** Generate id at resource string */
222 APT_DECLARE(apt_bool_t) apt_id_resource_generate(const apt_str_t *id, const apt_str_t *resource, char separator, apt_str_t *str, apr_pool_t *pool);
223 
224 /** Generate value plus the length (number of digits) of the value itself */
225 APT_DECLARE(apt_bool_t) apt_var_length_value_generate(apr_size_t *value, apr_size_t max_count, apt_str_t *str);
226 
227 /** Generate completion-cause */
228 APT_DECLARE(apt_bool_t) apt_completion_cause_generate(const apt_str_table_item_t table[], apr_size_t size, apr_size_t cause, apt_str_t *str, apr_pool_t *pool);
229 
230 /**
231  * Generate unique identifier (hex string)
232  * @param id the id to generate
233  * @param length the length of hex string to generate
234  * @param pool the pool to allocate memory from
235  */
236 APT_DECLARE(apt_bool_t) apt_unique_id_generate(apt_str_t *id, apr_size_t length, apr_pool_t *pool);
237 
238 
239 APT_END_EXTERN_C
240 
241 #endif /* APT_TEXT_STREAM_H */
242