1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8-*- */
3 /*
4 * This file is part of The Croco Library
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2.1 of the GNU Lesser General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 * USA
19 *
20 * Author: Dodji Seketeli
21 * See COPYRIGHTS file for copyright information.
22 */
24 #include "stdio.h"
25 #include <string.h>
26 #include "cr-input.h"
27 #include "cr-enc-handler.h"
29 /**
30 *@file
31 *The definition of the #CRInput class.
32 */
34 /*******************
35 *Private type defs
36 *******************/
38 /**
39 *The private attributes of
40 *the #CRInputPriv class.
41 */
42 struct _CRInputPriv {
43 /*
44 *The input buffer
45 */
46 guchar *in_buf;
47 gulong in_buf_size;
49 gulong nb_bytes;
51 /*
52 *The index of the next byte
53 *to be read.
54 */
55 gulong next_byte_index;
57 /*
58 *The current line number
59 */
60 gulong line;
62 /*
63 *The current col number
64 */
65 gulong col;
67 gboolean end_of_line;
68 gboolean end_of_input;
70 /*
71 *the reference count of this
72 *instance.
73 */
74 guint ref_count;
75 gboolean free_in_buf;
76 };
78 #define PRIVATE(object) (object)->priv
80 /***************************
81 *private constants
82 **************************/
83 #define CR_INPUT_MEM_CHUNK_SIZE 1024 * 4
85 static CRInput *cr_input_new_real (void);
87 static CRInput *
88 cr_input_new_real (void)
89 {
90 CRInput *result = NULL;
92 result = g_try_malloc (sizeof (CRInput));
93 if (!result) {
94 cr_utils_trace_info ("Out of memory");
95 return NULL;
96 }
97 memset (result, 0, sizeof (CRInput));
99 PRIVATE (result) = g_try_malloc (sizeof (CRInputPriv));
100 if (!PRIVATE (result)) {
101 cr_utils_trace_info ("Out of memory");
102 g_free (result);
103 return NULL;
104 }
105 memset (PRIVATE (result), 0, sizeof (CRInputPriv));
106 PRIVATE (result)->free_in_buf = TRUE;
107 return result;
108 }
110 /****************
111 *Public methods
112 ***************/
114 /**
115 *Creates a new input stream from a memory buffer.
116 *@param a_buf the memory buffer to create the input stream from.
117 *The #CRInput keeps this pointer so user should not free it !.
118 *@param a_len the size of the input buffer.
119 *@param a_enc the buffer's encoding.
120 *@param a_free_buf if set to TRUE, this a_buf will be freed
121 *at the destruction of this instance. If set to false, it is up
122 *to the caller to free it.
123 *@return the newly built instance of #CRInput.
124 */
125 CRInput *
126 cr_input_new_from_buf (guchar * a_buf,
127 gulong a_len,
128 enum CREncoding a_enc,
129 gboolean a_free_buf)
130 {
131 CRInput *result = NULL;
132 enum CRStatus status = CR_OK;
133 CREncHandler *enc_handler = NULL;
134 gulong len = a_len;
136 g_return_val_if_fail (a_buf, NULL);
138 result = cr_input_new_real ();
139 g_return_val_if_fail (result, NULL);
141 /*transform the encoding in utf8 */
142 if (a_enc != CR_UTF_8) {
143 enc_handler = cr_enc_handler_get_instance (a_enc);
144 if (!enc_handler) {
145 goto error;
146 }
148 status = cr_enc_handler_convert_input
149 (enc_handler, a_buf, &len,
150 &PRIVATE (result)->in_buf,
151 &PRIVATE (result)->in_buf_size);
152 if (status != CR_OK)
153 goto error;
154 PRIVATE (result)->free_in_buf = TRUE;
155 if (a_free_buf == TRUE && a_buf) {
156 g_free (a_buf) ;
157 a_buf = NULL ;
158 }
159 PRIVATE (result)->nb_bytes = PRIVATE (result)->in_buf_size;
160 } else {
161 PRIVATE (result)->in_buf = (guchar *) a_buf;
162 PRIVATE (result)->in_buf_size = a_len;
163 PRIVATE (result)->nb_bytes = a_len;
164 PRIVATE (result)->free_in_buf = a_free_buf;
165 }
166 PRIVATE (result)->line = 1;
167 PRIVATE (result)->col = 0;
168 return result;
170 error:
171 if (result) {
172 cr_input_destroy (result);
173 result = NULL;
174 }
176 return NULL;
177 }
179 /**
180 *Creates a new input stream from
181 *a file.
182 *@param a_file_uri the file to create
183 *the input stream from.
184 *@param a_enc the encoding of the file
185 *to create the input from
186 *@return the newly created input stream if
187 *this method could read the file and create it,
188 *NULL otherwise.
189 */
191 CRInput *
192 cr_input_new_from_uri (const gchar * a_file_uri, enum CREncoding a_enc)
193 {
194 CRInput *result = NULL;
195 enum CRStatus status = CR_OK;
196 FILE *file_ptr = NULL;
197 guchar tmp_buf[CR_INPUT_MEM_CHUNK_SIZE] = { 0 };
198 gulong nb_read = 0,
199 len = 0,
200 buf_size = 0;
201 gboolean loop = TRUE;
202 guchar *buf = NULL;
204 g_return_val_if_fail (a_file_uri, NULL);
206 file_ptr = fopen (a_file_uri, "r");
208 if (file_ptr == NULL) {
210 #ifdef CR_DEBUG
211 cr_utils_trace_debug ("could not open file");
212 #endif
213 g_warning ("Could not open file %s\n", a_file_uri);
215 return NULL;
216 }
218 /*load the file */
219 while (loop) {
220 nb_read = fread (tmp_buf, 1 /*read bytes */ ,
221 CR_INPUT_MEM_CHUNK_SIZE /*nb of bytes */ ,
222 file_ptr);
224 if (nb_read != CR_INPUT_MEM_CHUNK_SIZE) {
225 /*we read less chars than we wanted */
226 if (feof (file_ptr)) {
227 /*we reached eof */
228 loop = FALSE;
229 } else {
230 /*a pb occured !! */
231 cr_utils_trace_debug ("an io error occured");
232 status = CR_ERROR;
233 goto cleanup;
234 }
235 }
237 if (status == CR_OK) {
238 /*read went well */
239 buf = g_realloc (buf, len + CR_INPUT_MEM_CHUNK_SIZE);
240 memcpy (buf + len, tmp_buf, nb_read);
241 len += nb_read;
242 buf_size += CR_INPUT_MEM_CHUNK_SIZE;
243 }
244 }
246 if (status == CR_OK) {
247 result = cr_input_new_from_buf (buf, len, a_enc, TRUE);
248 if (!result) {
249 goto cleanup;
250 }
251 /*
252 *we should free buf here because it's own by CRInput.
253 *(see the last parameter of cr_input_new_from_buf().
254 */
255 buf = NULL ;
256 }
258 cleanup:
259 if (file_ptr) {
260 fclose (file_ptr);
261 file_ptr = NULL;
262 }
264 if (buf) {
265 g_free (buf);
266 buf = NULL;
267 }
269 return result;
270 }
272 /**
273 *The destructor of the #CRInput class.
274 *@param a_this the current instance of #CRInput.
275 */
276 void
277 cr_input_destroy (CRInput * a_this)
278 {
279 if (a_this == NULL)
280 return;
282 if (PRIVATE (a_this)) {
283 if (PRIVATE (a_this)->in_buf && PRIVATE (a_this)->free_in_buf) {
284 g_free (PRIVATE (a_this)->in_buf);
285 PRIVATE (a_this)->in_buf = NULL;
286 }
288 g_free (PRIVATE (a_this));
289 PRIVATE (a_this) = NULL;
290 }
292 g_free (a_this);
293 }
295 /**
296 *Increments the reference count of the current
297 *instance of #CRInput.
298 *@param a_this the current instance of #CRInput.
299 */
300 void
301 cr_input_ref (CRInput * a_this)
302 {
303 g_return_if_fail (a_this && PRIVATE (a_this));
305 PRIVATE (a_this)->ref_count++;
306 }
308 /**
309 *Decrements the reference count of this instance
310 *of #CRInput. If the reference count goes down to
311 *zero, this instance is destroyed.
312 *@param a_this the current instance of #CRInput.
313 *
314 */
315 gboolean
316 cr_input_unref (CRInput * a_this)
317 {
318 g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);
320 if (PRIVATE (a_this)->ref_count) {
321 PRIVATE (a_this)->ref_count--;
322 }
324 if (PRIVATE (a_this)->ref_count == 0) {
325 cr_input_destroy (a_this);
326 return TRUE;
327 }
328 return FALSE;
329 }
331 /**
332 *Tests wether the current instance of
333 *#CRInput has reached its input buffer.
334 *@param a_this the current instance of #CRInput.
335 *@param a_end_of_input out parameter. Is set to TRUE if
336 *the current instance has reached the end of its input buffer,
337 *FALSE otherwise.
338 *@param CR_OK upon successful completion, an error code otherwise.
339 *Note that all the out parameters of this method are valid if
340 *and only if this method returns CR_OK.
341 */
342 enum CRStatus
343 cr_input_end_of_input (CRInput * a_this, gboolean * a_end_of_input)
344 {
345 g_return_val_if_fail (a_this && PRIVATE (a_this)
346 && a_end_of_input, CR_BAD_PARAM_ERROR);
348 *a_end_of_input = (PRIVATE (a_this)->next_byte_index
349 >= PRIVATE (a_this)->in_buf_size) ? TRUE : FALSE;
351 return CR_OK;
352 }
354 /**
355 *Returns the number of bytes left in the input stream
356 *before the end.
357 *@param a_this the current instance of #CRInput.
358 *@return the number of characters left or -1 in case of error.
359 */
360 glong
361 cr_input_get_nb_bytes_left (CRInput * a_this)
362 {
363 g_return_val_if_fail (a_this && PRIVATE (a_this), -1);
364 g_return_val_if_fail (PRIVATE (a_this)->nb_bytes
365 <= PRIVATE (a_this)->in_buf_size, -1);
366 g_return_val_if_fail (PRIVATE (a_this)->next_byte_index
367 <= PRIVATE (a_this)->nb_bytes, -1);
369 if (PRIVATE (a_this)->end_of_input)
370 return 0;
372 return PRIVATE (a_this)->nb_bytes - PRIVATE (a_this)->next_byte_index;
373 }
375 /**
376 *Returns the next byte of the input.
377 *Update the state of the input so that
378 *the next invocation of this method returns
379 *the next coming byte.
380 *
381 *@param a_this the current instance of #CRInput.
382 *@param a_byte out parameter the returned byte.
383 *@return CR_OK upon successful completion, an error code
384 *otherwise. All the out parameters of this method are valid if
385 *and only if this method returns CR_OK.
386 */
387 enum CRStatus
388 cr_input_read_byte (CRInput * a_this, guchar * a_byte)
389 {
390 g_return_val_if_fail (a_this && PRIVATE (a_this)
391 && a_byte, CR_BAD_PARAM_ERROR);
393 g_return_val_if_fail (PRIVATE (a_this)->next_byte_index <=
394 PRIVATE (a_this)->nb_bytes, CR_BAD_PARAM_ERROR);
396 if (PRIVATE (a_this)->end_of_input == TRUE)
397 return CR_END_OF_INPUT_ERROR;
399 *a_byte = PRIVATE (a_this)->in_buf[PRIVATE (a_this)->next_byte_index];
401 if (PRIVATE (a_this)->nb_bytes -
402 PRIVATE (a_this)->next_byte_index < 2) {
403 PRIVATE (a_this)->end_of_input = TRUE;
404 } else {
405 PRIVATE (a_this)->next_byte_index++;
406 }
408 return CR_OK;
409 }
411 /**
412 *Reads an unicode character from the current instance of
413 *#CRInput.
414 *@param a_this the current instance of CRInput.
415 *@param a_char out parameter. The read character.
416 *@return CR_OK upon successful completion, an error code
417 *otherwise.
418 */
419 enum CRStatus
420 cr_input_read_char (CRInput * a_this, guint32 * a_char)
421 {
422 enum CRStatus status = CR_OK;
423 gulong consumed = 0,
424 nb_bytes_left = 0;
426 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
427 CR_BAD_PARAM_ERROR);
429 if (PRIVATE (a_this)->end_of_input == TRUE)
430 return CR_END_OF_INPUT_ERROR;
432 nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
434 if (nb_bytes_left < 1) {
435 return CR_END_OF_INPUT_ERROR;
436 }
438 status = cr_utils_read_char_from_utf8_buf
439 (PRIVATE (a_this)->in_buf
440 +
441 PRIVATE (a_this)->next_byte_index,
442 nb_bytes_left, a_char, &consumed);
444 if (status == CR_OK) {
445 /*update next byte index */
446 PRIVATE (a_this)->next_byte_index += consumed;
448 /*update line and column number */
449 if (PRIVATE (a_this)->end_of_line == TRUE) {
450 PRIVATE (a_this)->col = 1;
451 PRIVATE (a_this)->line++;
452 PRIVATE (a_this)->end_of_line = FALSE;
453 } else if (*a_char != '\n') {
454 PRIVATE (a_this)->col++;
455 }
457 if (*a_char == '\n') {
458 PRIVATE (a_this)->end_of_line = TRUE;
459 }
461 }
463 return status;
464 }
466 /**
467 *Setter of the current line number.
468 *@param a_this the "this pointer" of the current instance of
469 *#CRInput.
470 *@param a_line_num the new line number.
471 *@return CR_OK upon successful completion, an error code otherwise.
472 */
473 enum CRStatus
474 cr_input_set_line_num (CRInput * a_this, glong a_line_num)
475 {
476 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
478 PRIVATE (a_this)->line = a_line_num;
480 return CR_OK;
481 }
483 /**
484 *Getter of the current line number.
485 *@param a_this the "this pointer" of the current instance of
486 *#CRInput.
487 *@param a_line_num the returned line number.
488 *@return CR_OK upon successful completion, an error code otherwise.
489 */
490 enum CRStatus
491 cr_input_get_line_num (CRInput * a_this, glong * a_line_num)
492 {
493 g_return_val_if_fail (a_this && PRIVATE (a_this)
494 && a_line_num, CR_BAD_PARAM_ERROR);
496 *a_line_num = PRIVATE (a_this)->line;
498 return CR_OK;
499 }
501 /**
502 *Setter of the current column number.
503 *@param a_this the "this pointer" of the current instance of
504 *#CRInput.
505 *@param a_col the new column number.
506 *@return CR_OK upon successful completion, an error code otherwise.
507 */
508 enum CRStatus
509 cr_input_set_column_num (CRInput * a_this, glong a_col)
510 {
511 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
513 PRIVATE (a_this)->col = a_col;
515 return CR_OK;
516 }
518 /**
519 *Getter of the current column number.
520 *@param a_this the "this pointer" of the current instance of
521 *#CRInput.
522 *@param a_col out parameter
523 *@return CR_OK upon successful completion, an error code otherwise.
524 */
525 enum CRStatus
526 cr_input_get_column_num (CRInput * a_this, glong * a_col)
527 {
528 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_col,
529 CR_BAD_PARAM_ERROR);
531 *a_col = PRIVATE (a_this)->col;
533 return CR_OK;
534 }
536 /**
537 *Increments the current line number.
538 *@param a_this the "this pointer" of the current instance of
539 *#CRInput.
540 *@return CR_OK upon successful completion, an error code otherwise.
541 */
542 enum CRStatus
543 cr_input_increment_line_num (CRInput * a_this, glong a_increment)
544 {
545 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
547 PRIVATE (a_this)->line += a_increment;
549 return CR_OK;
550 }
552 /**
553 *Increments the current column number.
554 *@param a_this the "this pointer" of the current instance of
555 *#CRInput.
556 *@return CR_OK upon successful completion, an error code otherwise.
557 */
558 enum CRStatus
559 cr_input_increment_col_num (CRInput * a_this, glong a_increment)
560 {
561 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
563 PRIVATE (a_this)->col += a_increment;
565 return CR_OK;
566 }
568 /**
569 *Consumes the next character of the input stream if
570 *and only if that character equals a_char.
571 *
572 *@param a_this the this pointer.
573 *@param a_char the character to consume. If set to zero,
574 *consumes any character.
575 *@return CR_OK upon successful completion, CR_PARSING_ERROR if
576 *next char is different from a_char, an other error code otherwise
577 */
578 enum CRStatus
579 cr_input_consume_char (CRInput * a_this, guint32 a_char)
580 {
581 guint32 c;
582 enum CRStatus status;
584 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
586 if ((status = cr_input_peek_char (a_this, &c)) != CR_OK) {
587 return status;
588 }
590 if (c == a_char || a_char == 0) {
591 status = cr_input_read_char (a_this, &c);
592 } else {
593 return CR_PARSING_ERROR;
594 }
596 return status;
597 }
599 /**
600 *Consumes up to a_nb_char occurences of the next contiguous characters
601 *which equal a_char. Note that the next character of the input stream
602 **MUST* equal a_char to trigger the consumption, or else, the error
603 *code CR_PARSING_ERROR is returned.
604 *If the number of contiguous characters that equals a_char is less than
605 *a_nb_char, then this function consumes all the characters it can consume.
606 *
607 *@param a_this the this pointer of the current instance of #CRInput.
608 *@param a_char the character to consume.
609 *@param a_nb_char in/out parameter. The number of characters to consume.
610 *If set to a negative value, the function will consume all the occurences
611 *of a_char found.
612 *After return, if the return value equals CR_OK, this variable contains
613 *the number of characters actually consumed.
614 *@return CR_OK if at least one character has been consumed, an error code
615 *otherwise.
616 */
617 enum CRStatus
618 cr_input_consume_chars (CRInput * a_this, guint32 a_char, gulong * a_nb_char)
619 {
620 enum CRStatus status = CR_OK;
621 gulong nb_consumed = 0;
623 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char,
624 CR_BAD_PARAM_ERROR);
626 g_return_val_if_fail (a_char != 0 || a_nb_char != NULL,
627 CR_BAD_PARAM_ERROR);
629 for (nb_consumed = 0; ((status == CR_OK)
630 && (*a_nb_char > 0
631 && nb_consumed < *a_nb_char));
632 nb_consumed++) {
633 status = cr_input_consume_char (a_this, a_char);
634 }
636 *a_nb_char = nb_consumed;
638 if ((nb_consumed > 0)
639 && ((status == CR_PARSING_ERROR)
640 || (status == CR_END_OF_INPUT_ERROR))) {
641 status = CR_OK;
642 }
644 return status;
645 }
647 /**
648 *Same as cr_input_consume_chars() but this one consumes white
649 *spaces.
650 *
651 *@param a_this the "this pointer" of the current instance of #CRInput.
652 *@param a_nb_chars in/out parameter. The number of white spaces to
653 *consume. After return, holds the number of white spaces actually consumed.
654 *@return CR_OK upon successful completion, an error code otherwise.
655 */
656 enum CRStatus
657 cr_input_consume_white_spaces (CRInput * a_this, gulong * a_nb_chars)
658 {
659 enum CRStatus status = CR_OK;
660 guint32 cur_char = 0,
661 nb_consumed = 0;
663 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_chars,
664 CR_BAD_PARAM_ERROR);
666 for (nb_consumed = 0;
667 ((*a_nb_chars > 0) && (nb_consumed < *a_nb_chars));
668 nb_consumed++) {
669 status = cr_input_peek_char (a_this, &cur_char);
670 if (status != CR_OK)
671 break;
673 /*if the next char is a white space, consume it ! */
674 if (cr_utils_is_white_space (cur_char) == TRUE) {
675 status = cr_input_read_char (a_this, &cur_char);
676 if (status != CR_OK)
677 break;
678 continue;
679 }
681 break;
683 }
685 if (nb_consumed && status == CR_END_OF_INPUT_ERROR) {
686 status = CR_OK;
687 }
689 return status;
690 }
692 /**
693 *Same as cr_input_read_char() but does not update the
694 *internal state of the input stream. The next call
695 *to cr_input_peek_char() or cr_input_read_char() will thus
696 *return the same character as the current one.
697 *@param a_this the current instance of #CRInput.
698 *@param a_char out parameter. The returned character.
699 *@return CR_OK upon successful completion, an error code
700 *otherwise.
701 */
702 enum CRStatus
703 cr_input_peek_char (CRInput * a_this, guint32 * a_char)
704 {
705 enum CRStatus status = CR_OK;
706 glong consumed = 0,
707 nb_bytes_left = 0;
709 g_return_val_if_fail (a_this && PRIVATE (a_this)
710 && a_char, CR_BAD_PARAM_ERROR);
712 if (PRIVATE (a_this)->next_byte_index >=
713 PRIVATE (a_this)->in_buf_size) {
714 return CR_END_OF_INPUT_ERROR;
715 }
717 nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
719 if (nb_bytes_left < 1) {
720 return CR_END_OF_INPUT_ERROR;
721 }
723 status = cr_utils_read_char_from_utf8_buf
724 (PRIVATE (a_this)->in_buf +
725 PRIVATE (a_this)->next_byte_index,
726 nb_bytes_left, a_char, &consumed);
728 return status;
729 }
731 /**
732 *Gets a byte from the input stream,
733 *starting from the current position in the input stream.
734 *Unlike cr_input_peek_next_byte() this method
735 *does not update the state of the current input stream.
736 *Subsequent calls to cr_input_peek_byte with the same arguments
737 *will return the same byte.
738 *
739 *@param a_this the current instance of #CRInput.
740 *@param a_origin the origin to consider in the calculation
741 *of the position of the byte to peek.
742 *@param a_offset the offset of the byte to peek, starting from
743 *the origin specified by a_origin.
744 *@param a_byte out parameter the peeked byte.
745 *@return CR_OK upon successful completion or,
746 *
747 *<ul>
748 *<li>CR_BAD_PARAM_ERROR if at least one of the parameters is invalid</li>
749 *<li>CR_OUT_OF_BOUNDS_ERROR if the indexed byte is out of bounds</li>
750 *</ul>
751 */
752 enum CRStatus
753 cr_input_peek_byte (CRInput * a_this, enum CRSeekPos a_origin,
754 gulong a_offset, guchar * a_byte)
755 {
756 gulong abs_offset = 0;
758 g_return_val_if_fail (a_this && PRIVATE (a_this)
759 && a_byte, CR_BAD_PARAM_ERROR);
761 switch (a_origin) {
763 case CR_SEEK_CUR:
764 abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_offset;
765 break;
767 case CR_SEEK_BEGIN:
768 abs_offset = a_offset;
769 break;
771 case CR_SEEK_END:
772 abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_offset;
773 break;
775 default:
776 return CR_BAD_PARAM_ERROR;
777 }
779 if (abs_offset < PRIVATE (a_this)->in_buf_size) {
781 *a_byte = PRIVATE (a_this)->in_buf[abs_offset];
783 return CR_OK;
785 } else {
786 return CR_END_OF_INPUT_ERROR;
787 }
788 }
790 /**
791 *Same as cr_input_peek_byte() but with a simplified
792 *interface.
793 *@param a_this the current byte input stream.
794 *@param a_offset the offset of the byte to peek, starting
795 *from the current input position pointer.
796 *@param a_eof out parameter. Is set to true is we reach end of
797 *stream. If set to NULL by the caller, this parameter is not taken
798 *in account.
799 *@return the read byte or 0 if something bad happened.
800 */
801 guchar
802 cr_input_peek_byte2 (CRInput * a_this, gulong a_offset, gboolean * a_eof)
803 {
804 guchar result = 0;
805 enum CRStatus status = CR_ERROR;
807 g_return_val_if_fail (a_this && PRIVATE (a_this), 0);
809 if (a_eof)
810 *a_eof = FALSE;
812 status = cr_input_peek_byte (a_this, CR_SEEK_CUR, a_offset, &result);
814 if ((status == CR_END_OF_INPUT_ERROR)
815 && a_eof)
816 *a_eof = TRUE;
818 return result;
819 }
821 /**
822 *Returns the memory address of the byte located at a given offset
823 *in the input stream.
824 *@param a_this the current instance of #CRInput.
825 *@param a_offset the offset of the byte in the input stream starting
826 *from the beginning of the stream.
827 *@return the address, otherwise NULL if an error occured.
828 */
829 guchar *
830 cr_input_get_byte_addr (CRInput * a_this, gulong a_offset)
831 {
832 g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
834 if (a_offset >= PRIVATE (a_this)->nb_bytes) {
835 return NULL;
836 }
838 return &PRIVATE (a_this)->in_buf[a_offset];
839 }
841 /**
842 *Returns the address of the current character pointer.
843 *@param a_this the current input stream
844 *@param a_offset out parameter. The returned address.
845 *@return CR_OK upon successful completion, an error code otherwise.
846 */
847 enum CRStatus
848 cr_input_get_cur_byte_addr (CRInput * a_this, guchar ** a_offset)
849 {
850 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_offset,
851 CR_BAD_PARAM_ERROR);
853 if (!PRIVATE (a_this)->next_byte_index) {
854 return CR_START_OF_INPUT_ERROR;
855 }
857 *a_offset = cr_input_get_byte_addr
858 (a_this, PRIVATE (a_this)->next_byte_index - 1);
860 return CR_OK;
861 }
863 /**
864 *Sets the "current byte index" of the current instance
865 *of #CRInput. Next call to cr_input_get_byte() will return
866 *the byte next after the new "current byte index".
867 *
868 *@param a_this the current instance of #CRInput.
869 *
870 *@param a_origin the origin to consider during the calculation
871 *of the absolute position of the new "current byte index".
872 *
873 *@param a_pos the relative offset of the new "current byte index."
874 *This offset is relative to the origin a_origin.
875 *
876 *@return CR_OK upon successful completion otherwise returns
877 *<ul>
878 *<li>CR_BAD_PARAM_ERROR if at least one of the parameters is not valid</li>
879 *<li>CR_OUT_BOUNDS_ERROR</li>
880 *</ul>
881 */
882 enum CRStatus
883 cr_input_seek_index (CRInput * a_this, enum CRSeekPos a_origin, gint a_pos)
884 {
886 glong abs_offset = 0;
888 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
890 switch (a_origin) {
892 case CR_SEEK_CUR:
893 abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_pos;
894 break;
896 case CR_SEEK_BEGIN:
897 abs_offset = a_pos;
898 break;
900 case CR_SEEK_END:
901 abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_pos;
902 break;
904 default:
905 return CR_BAD_PARAM_ERROR;
906 }
908 if ((abs_offset > 0)
909 && (gulong) abs_offset < PRIVATE (a_this)->nb_bytes) {
911 /*update the input stream's internal state */
912 PRIVATE (a_this)->next_byte_index = abs_offset + 1;
914 return CR_OK;
915 }
917 return CR_OUT_OF_BOUNDS_ERROR;
918 }
920 /**
921 *Gets the position of the "current byte index" which
922 *is basically the position of the last returned byte in the
923 *input stream.
924 *
925 *@param a_this the current instance of #CRInput.
926 *
927 *@param a_pos out parameter. The returned position.
928 *
929 *@return CR_OK upon successful completion. Otherwise,
930 *<ul>
931 *<li>CR_BAD_PARAMETER_ERROR if at least one of the arguments is invalid.</li>
932 *<li>CR_START_OF_INPUT if no call to either cr_input_read_byte()
933 *or cr_input_seek_index() have been issued before calling
934 *cr_input_get_cur_pos()</li>
935 *</ul>
936 *Note that the out parameters of this function are valid if and only if this
937 *function returns CR_OK.
938 */
939 enum CRStatus
940 cr_input_get_cur_pos (CRInput * a_this, CRInputPos * a_pos)
941 {
942 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
943 CR_BAD_PARAM_ERROR);
945 a_pos->next_byte_index = PRIVATE (a_this)->next_byte_index;
946 a_pos->line = PRIVATE (a_this)->line;
947 a_pos->col = PRIVATE (a_this)->col;
948 a_pos->end_of_line = PRIVATE (a_this)->end_of_line;
949 a_pos->end_of_file = PRIVATE (a_this)->end_of_input;
951 return CR_OK;
952 }
954 /**
955 *Gets the current parsing location.
956 *The Parsing location is a public datastructure that
957 *represents the current line/column/byte offset/ in the input
958 *stream.
959 *@param a_this the current instance of #CRInput
960 *@param a_loc the set parsing location.
961 *@return CR_OK upon successful completion, an error
962 *code otherwise.
963 */
964 enum CRStatus
965 cr_input_get_parsing_location (CRInput *a_this,
966 CRParsingLocation *a_loc)
967 {
968 g_return_val_if_fail (a_this
969 && PRIVATE (a_this)
970 && a_loc,
971 CR_BAD_PARAM_ERROR) ;
973 a_loc->line = PRIVATE (a_this)->line ;
974 a_loc->column = PRIVATE (a_this)->col ;
975 if (PRIVATE (a_this)->next_byte_index) {
976 a_loc->byte_offset = PRIVATE (a_this)->next_byte_index - 1 ;
977 } else {
978 a_loc->byte_offset = PRIVATE (a_this)->next_byte_index ;
979 }
980 return CR_OK ;
981 }
983 /**
984 *Getter of the next byte index.
985 *It actually returns the index of the
986 *next byte to be read.
987 *@param a_this the "this pointer" of the current instance of
988 *#CRInput
989 *@param a_index out parameter. The returned index.
990 *@return CR_OK upon successful completion, an error code
991 *otherwise.
992 */
993 enum CRStatus
994 cr_input_get_cur_index (CRInput * a_this, glong * a_index)
995 {
996 g_return_val_if_fail (a_this && PRIVATE (a_this)
997 && a_index, CR_BAD_PARAM_ERROR);
999 *a_index = PRIVATE (a_this)->next_byte_index;
1001 return CR_OK;
1002 }
1004 /**
1005 *Setter of the next byte index.
1006 *It sets the index of the next byte to be read.
1007 *@param a_this the "this pointer" of the current instance
1008 *of #CRInput .
1009 *@param a_index the new index to set.
1010 *@return CR_OK upon successful completion, an error code otherwise.
1011 */
1012 enum CRStatus
1013 cr_input_set_cur_index (CRInput * a_this, glong a_index)
1014 {
1015 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1017 PRIVATE (a_this)->next_byte_index = a_index;
1019 return CR_OK;
1020 }
1022 /**
1023 *Sets the end of file flag.
1024 *@param a_this the current instance of #CRInput.
1025 *@param a_eof the new end of file flag.
1026 *@return CR_OK upon successful completion, an error code otherwise.
1027 */
1028 enum CRStatus
1029 cr_input_set_end_of_file (CRInput * a_this, gboolean a_eof)
1030 {
1031 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1033 PRIVATE (a_this)->end_of_input = a_eof;
1035 return CR_OK;
1036 }
1038 /**
1039 *Gets the end of file flag.
1040 *@param a_this the current instance of #CRInput.
1041 *@param a_eof out parameter the place to put the end of
1042 *file flag.
1043 *@return CR_OK upon successful completion, an error code otherwise.
1044 */
1045 enum CRStatus
1046 cr_input_get_end_of_file (CRInput * a_this, gboolean * a_eof)
1047 {
1048 g_return_val_if_fail (a_this && PRIVATE (a_this)
1049 && a_eof, CR_BAD_PARAM_ERROR);
1051 *a_eof = PRIVATE (a_this)->end_of_input;
1053 return CR_OK;
1054 }
1056 /**
1057 *Sets the end of line flag.
1058 *@param a_this the current instance of #CRInput.
1059 *@param a_eol the new end of line flag.
1060 *@return CR_OK upon successful completion, an error code
1061 *otherwise.
1062 */
1063 enum CRStatus
1064 cr_input_set_end_of_line (CRInput * a_this, gboolean a_eol)
1065 {
1066 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1068 PRIVATE (a_this)->end_of_line = a_eol;
1070 return CR_OK;
1071 }
1073 /**
1074 *Gets the end of line flag of the current input.
1075 *@param a_this the current instance of #CRInput
1076 *@param a_eol out parameter. The place to put
1077 *the returned flag
1078 *@return CR_OK upon successful completion, an error code
1079 *otherwise.
1080 */
1081 enum CRStatus
1082 cr_input_get_end_of_line (CRInput * a_this, gboolean * a_eol)
1083 {
1084 g_return_val_if_fail (a_this && PRIVATE (a_this)
1085 && a_eol, CR_BAD_PARAM_ERROR);
1087 *a_eol = PRIVATE (a_this)->end_of_line;
1089 return CR_OK;
1090 }
1092 /**
1093 *Sets the current position in the input stream.
1094 *
1095 *@param a_this the "this pointer" of the current instance of
1096 *#CRInput.
1097 *@param a_pos the new position.
1098 */
1099 enum CRStatus
1100 cr_input_set_cur_pos (CRInput * a_this, CRInputPos * a_pos)
1101 {
1102 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
1103 CR_BAD_PARAM_ERROR);
1105 cr_input_set_column_num (a_this, a_pos->col);
1106 cr_input_set_line_num (a_this, a_pos->line);
1107 cr_input_set_cur_index (a_this, a_pos->next_byte_index);
1108 cr_input_set_end_of_line (a_this, a_pos->end_of_line);
1109 cr_input_set_end_of_file (a_this, a_pos->end_of_file);
1111 return CR_OK;
1112 }