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 = (CRInput *)g_try_malloc (sizeof (CRInput));
91 if (!result) {
92 cr_utils_trace_info ("Out of memory");
93 return NULL;
94 }
95 memset (result, 0, sizeof (CRInput));
97 PRIVATE (result) = (CRInputPriv *)g_try_malloc (sizeof (CRInputPriv));
98 if (!PRIVATE (result)) {
99 cr_utils_trace_info ("Out of memory");
100 g_free (result);
101 return NULL;
102 }
103 memset (PRIVATE (result), 0, sizeof (CRInputPriv));
104 PRIVATE (result)->free_in_buf = TRUE;
105 return result;
106 }
108 /****************
109 *Public methods
110 ***************/
112 /**
113 *Creates a new input stream from a memory buffer.
114 *@param a_buf the memory buffer to create the input stream from.
115 *The #CRInput keeps this pointer so user should not free it !.
116 *@param a_len the size of the input buffer.
117 *@param a_enc the buffer's encoding.
118 *@param a_free_buf if set to TRUE, this a_buf will be freed
119 *at the destruction of this instance. If set to false, it is up
120 *to the caller to free it.
121 *@return the newly built instance of #CRInput.
122 */
123 CRInput *
124 cr_input_new_from_buf (guchar * a_buf,
125 gulong a_len,
126 enum CREncoding a_enc,
127 gboolean a_free_buf)
128 {
129 CRInput *result = NULL;
130 enum CRStatus status = CR_OK;
131 CREncHandler *enc_handler = NULL;
132 gulong len = a_len;
134 g_return_val_if_fail (a_buf, NULL);
136 result = cr_input_new_real ();
137 g_return_val_if_fail (result, NULL);
139 /*transform the encoding in utf8 */
140 if (a_enc != CR_UTF_8) {
141 enc_handler = cr_enc_handler_get_instance (a_enc);
142 if (!enc_handler) {
143 goto error;
144 }
146 status = cr_enc_handler_convert_input
147 (enc_handler, a_buf, &len,
148 &PRIVATE (result)->in_buf,
149 &PRIVATE (result)->in_buf_size);
150 if (status != CR_OK)
151 goto error;
152 PRIVATE (result)->free_in_buf = TRUE;
153 if (a_free_buf == TRUE && a_buf) {
154 g_free (a_buf) ;
155 a_buf = NULL ;
156 }
157 PRIVATE (result)->nb_bytes = PRIVATE (result)->in_buf_size;
158 } else {
159 PRIVATE (result)->in_buf = (guchar *) a_buf;
160 PRIVATE (result)->in_buf_size = a_len;
161 PRIVATE (result)->nb_bytes = a_len;
162 PRIVATE (result)->free_in_buf = a_free_buf;
163 }
164 PRIVATE (result)->line = 1;
165 PRIVATE (result)->col = 0;
166 return result;
168 error:
169 if (result) {
170 cr_input_destroy (result);
171 result = NULL;
172 }
174 return NULL;
175 }
177 /**
178 *Creates a new input stream from
179 *a file.
180 *@param a_file_uri the file to create
181 *the input stream from.
182 *@param a_enc the encoding of the file
183 *to create the input from
184 *@return the newly created input stream if
185 *this method could read the file and create it,
186 *NULL otherwise.
187 */
189 CRInput *
190 cr_input_new_from_uri (const gchar * a_file_uri, enum CREncoding a_enc)
191 {
192 CRInput *result = NULL;
193 enum CRStatus status = CR_OK;
194 FILE *file_ptr = NULL;
195 guchar tmp_buf[CR_INPUT_MEM_CHUNK_SIZE] = { 0 };
196 gulong nb_read = 0,
197 len = 0,
198 buf_size = 0;
199 gboolean loop = TRUE;
200 guchar *buf = NULL;
202 g_return_val_if_fail (a_file_uri, NULL);
204 file_ptr = fopen (a_file_uri, "r");
206 if (file_ptr == NULL) {
208 #ifdef CR_DEBUG
209 cr_utils_trace_debug ("could not open file");
210 #endif
211 g_warning ("Could not open file %s\n", a_file_uri);
213 return NULL;
214 }
216 /*load the file */
217 while (loop) {
218 nb_read = fread (tmp_buf, 1 /*read bytes */ ,
219 CR_INPUT_MEM_CHUNK_SIZE /*nb of bytes */ ,
220 file_ptr);
222 if (nb_read != CR_INPUT_MEM_CHUNK_SIZE) {
223 /*we read less chars than we wanted */
224 if (feof (file_ptr)) {
225 /*we reached eof */
226 loop = FALSE;
227 } else {
228 /*a pb occured !! */
229 cr_utils_trace_debug ("an io error occured");
230 status = CR_ERROR;
231 goto cleanup;
232 }
233 }
235 if (status == CR_OK) {
236 /*read went well */
237 buf = (guchar *)g_realloc (buf, len + CR_INPUT_MEM_CHUNK_SIZE);
238 memcpy (buf + len, tmp_buf, nb_read);
239 len += nb_read;
240 buf_size += CR_INPUT_MEM_CHUNK_SIZE;
241 }
242 }
244 if (status == CR_OK) {
245 result = cr_input_new_from_buf (buf, len, a_enc, TRUE);
246 if (!result) {
247 goto cleanup;
248 }
249 /*
250 *we should free buf here because it's own by CRInput.
251 *(see the last parameter of cr_input_new_from_buf().
252 */
253 buf = NULL ;
254 }
256 cleanup:
257 if (file_ptr) {
258 fclose (file_ptr);
259 file_ptr = NULL;
260 }
262 if (buf) {
263 g_free (buf);
264 buf = NULL;
265 }
267 return result;
268 }
270 /**
271 *The destructor of the #CRInput class.
272 *@param a_this the current instance of #CRInput.
273 */
274 void
275 cr_input_destroy (CRInput * a_this)
276 {
277 if (a_this == NULL)
278 return;
280 if (PRIVATE (a_this)) {
281 if (PRIVATE (a_this)->in_buf && PRIVATE (a_this)->free_in_buf) {
282 g_free (PRIVATE (a_this)->in_buf);
283 PRIVATE (a_this)->in_buf = NULL;
284 }
286 g_free (PRIVATE (a_this));
287 PRIVATE (a_this) = NULL;
288 }
290 g_free (a_this);
291 }
293 /**
294 *Increments the reference count of the current
295 *instance of #CRInput.
296 *@param a_this the current instance of #CRInput.
297 */
298 void
299 cr_input_ref (CRInput * a_this)
300 {
301 g_return_if_fail (a_this && PRIVATE (a_this));
303 PRIVATE (a_this)->ref_count++;
304 }
306 /**
307 *Decrements the reference count of this instance
308 *of #CRInput. If the reference count goes down to
309 *zero, this instance is destroyed.
310 *@param a_this the current instance of #CRInput.
311 *
312 */
313 gboolean
314 cr_input_unref (CRInput * a_this)
315 {
316 g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);
318 if (PRIVATE (a_this)->ref_count) {
319 PRIVATE (a_this)->ref_count--;
320 }
322 if (PRIVATE (a_this)->ref_count == 0) {
323 cr_input_destroy (a_this);
324 return TRUE;
325 }
326 return FALSE;
327 }
329 /**
330 *Tests wether the current instance of
331 *#CRInput has reached its input buffer.
332 *@param a_this the current instance of #CRInput.
333 *@param a_end_of_input out parameter. Is set to TRUE if
334 *the current instance has reached the end of its input buffer,
335 *FALSE otherwise.
336 *@param CR_OK upon successful completion, an error code otherwise.
337 *Note that all the out parameters of this method are valid if
338 *and only if this method returns CR_OK.
339 */
340 enum CRStatus
341 cr_input_end_of_input (CRInput * a_this, gboolean * a_end_of_input)
342 {
343 g_return_val_if_fail (a_this && PRIVATE (a_this)
344 && a_end_of_input, CR_BAD_PARAM_ERROR);
346 *a_end_of_input = (PRIVATE (a_this)->next_byte_index
347 >= PRIVATE (a_this)->in_buf_size) ? TRUE : FALSE;
349 return CR_OK;
350 }
352 /**
353 *Returns the number of bytes left in the input stream
354 *before the end.
355 *@param a_this the current instance of #CRInput.
356 *@return the number of characters left or -1 in case of error.
357 */
358 glong
359 cr_input_get_nb_bytes_left (CRInput * a_this)
360 {
361 g_return_val_if_fail (a_this && PRIVATE (a_this), -1);
362 g_return_val_if_fail (PRIVATE (a_this)->nb_bytes
363 <= PRIVATE (a_this)->in_buf_size, -1);
364 g_return_val_if_fail (PRIVATE (a_this)->next_byte_index
365 <= PRIVATE (a_this)->nb_bytes, -1);
367 if (PRIVATE (a_this)->end_of_input)
368 return 0;
370 return PRIVATE (a_this)->nb_bytes - PRIVATE (a_this)->next_byte_index;
371 }
373 /**
374 *Returns the next byte of the input.
375 *Update the state of the input so that
376 *the next invocation of this method returns
377 *the next coming byte.
378 *
379 *@param a_this the current instance of #CRInput.
380 *@param a_byte out parameter the returned byte.
381 *@return CR_OK upon successful completion, an error code
382 *otherwise. All the out parameters of this method are valid if
383 *and only if this method returns CR_OK.
384 */
385 enum CRStatus
386 cr_input_read_byte (CRInput * a_this, guchar * a_byte)
387 {
388 g_return_val_if_fail (a_this && PRIVATE (a_this)
389 && a_byte, CR_BAD_PARAM_ERROR);
391 g_return_val_if_fail (PRIVATE (a_this)->next_byte_index <=
392 PRIVATE (a_this)->nb_bytes, CR_BAD_PARAM_ERROR);
394 if (PRIVATE (a_this)->end_of_input == TRUE)
395 return CR_END_OF_INPUT_ERROR;
397 *a_byte = PRIVATE (a_this)->in_buf[PRIVATE (a_this)->next_byte_index];
399 if (PRIVATE (a_this)->nb_bytes -
400 PRIVATE (a_this)->next_byte_index < 2) {
401 PRIVATE (a_this)->end_of_input = TRUE;
402 } else {
403 PRIVATE (a_this)->next_byte_index++;
404 }
406 return CR_OK;
407 }
409 /**
410 *Reads an unicode character from the current instance of
411 *#CRInput.
412 *@param a_this the current instance of CRInput.
413 *@param a_char out parameter. The read character.
414 *@return CR_OK upon successful completion, an error code
415 *otherwise.
416 */
417 enum CRStatus
418 cr_input_read_char (CRInput * a_this, guint32 * a_char)
419 {
420 enum CRStatus status = CR_OK;
421 gulong consumed = 0,
422 nb_bytes_left = 0;
424 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
425 CR_BAD_PARAM_ERROR);
427 if (PRIVATE (a_this)->end_of_input == TRUE)
428 return CR_END_OF_INPUT_ERROR;
430 nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
432 if (nb_bytes_left < 1) {
433 return CR_END_OF_INPUT_ERROR;
434 }
436 status = cr_utils_read_char_from_utf8_buf
437 (PRIVATE (a_this)->in_buf
438 +
439 PRIVATE (a_this)->next_byte_index,
440 nb_bytes_left, a_char, &consumed);
442 if (status == CR_OK) {
443 /*update next byte index */
444 PRIVATE (a_this)->next_byte_index += consumed;
446 /*update line and column number */
447 if (PRIVATE (a_this)->end_of_line == TRUE) {
448 PRIVATE (a_this)->col = 1;
449 PRIVATE (a_this)->line++;
450 PRIVATE (a_this)->end_of_line = FALSE;
451 } else if (*a_char != '\n') {
452 PRIVATE (a_this)->col++;
453 }
455 if (*a_char == '\n') {
456 PRIVATE (a_this)->end_of_line = TRUE;
457 }
459 }
461 return status;
462 }
464 /**
465 *Setter of the current line number.
466 *@param a_this the "this pointer" of the current instance of
467 *#CRInput.
468 *@param a_line_num the new line number.
469 *@return CR_OK upon successful completion, an error code otherwise.
470 */
471 enum CRStatus
472 cr_input_set_line_num (CRInput * a_this, glong a_line_num)
473 {
474 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
476 PRIVATE (a_this)->line = a_line_num;
478 return CR_OK;
479 }
481 /**
482 *Getter of the current line number.
483 *@param a_this the "this pointer" of the current instance of
484 *#CRInput.
485 *@param a_line_num the returned line number.
486 *@return CR_OK upon successful completion, an error code otherwise.
487 */
488 enum CRStatus
489 cr_input_get_line_num (CRInput * a_this, glong * a_line_num)
490 {
491 g_return_val_if_fail (a_this && PRIVATE (a_this)
492 && a_line_num, CR_BAD_PARAM_ERROR);
494 *a_line_num = PRIVATE (a_this)->line;
496 return CR_OK;
497 }
499 /**
500 *Setter of the current column number.
501 *@param a_this the "this pointer" of the current instance of
502 *#CRInput.
503 *@param a_col the new column number.
504 *@return CR_OK upon successful completion, an error code otherwise.
505 */
506 enum CRStatus
507 cr_input_set_column_num (CRInput * a_this, glong a_col)
508 {
509 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
511 PRIVATE (a_this)->col = a_col;
513 return CR_OK;
514 }
516 /**
517 *Getter of the current column number.
518 *@param a_this the "this pointer" of the current instance of
519 *#CRInput.
520 *@param a_col out parameter
521 *@return CR_OK upon successful completion, an error code otherwise.
522 */
523 enum CRStatus
524 cr_input_get_column_num (CRInput * a_this, glong * a_col)
525 {
526 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_col,
527 CR_BAD_PARAM_ERROR);
529 *a_col = PRIVATE (a_this)->col;
531 return CR_OK;
532 }
534 /**
535 *Increments the current line number.
536 *@param a_this the "this pointer" of the current instance of
537 *#CRInput.
538 *@return CR_OK upon successful completion, an error code otherwise.
539 */
540 enum CRStatus
541 cr_input_increment_line_num (CRInput * a_this, glong a_increment)
542 {
543 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
545 PRIVATE (a_this)->line += a_increment;
547 return CR_OK;
548 }
550 /**
551 *Increments the current column number.
552 *@param a_this the "this pointer" of the current instance of
553 *#CRInput.
554 *@return CR_OK upon successful completion, an error code otherwise.
555 */
556 enum CRStatus
557 cr_input_increment_col_num (CRInput * a_this, glong a_increment)
558 {
559 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
561 PRIVATE (a_this)->col += a_increment;
563 return CR_OK;
564 }
566 /**
567 *Consumes the next character of the input stream if
568 *and only if that character equals a_char.
569 *
570 *@param a_this the this pointer.
571 *@param a_char the character to consume. If set to zero,
572 *consumes any character.
573 *@return CR_OK upon successful completion, CR_PARSING_ERROR if
574 *next char is different from a_char, an other error code otherwise
575 */
576 enum CRStatus
577 cr_input_consume_char (CRInput * a_this, guint32 a_char)
578 {
579 guint32 c;
580 enum CRStatus status;
582 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
584 if ((status = cr_input_peek_char (a_this, &c)) != CR_OK) {
585 return status;
586 }
588 if (c == a_char || a_char == 0) {
589 status = cr_input_read_char (a_this, &c);
590 } else {
591 return CR_PARSING_ERROR;
592 }
594 return status;
595 }
597 /**
598 *Consumes up to a_nb_char occurences of the next contiguous characters
599 *which equal a_char. Note that the next character of the input stream
600 **MUST* equal a_char to trigger the consumption, or else, the error
601 *code CR_PARSING_ERROR is returned.
602 *If the number of contiguous characters that equals a_char is less than
603 *a_nb_char, then this function consumes all the characters it can consume.
604 *
605 *@param a_this the this pointer of the current instance of #CRInput.
606 *@param a_char the character to consume.
607 *@param a_nb_char in/out parameter. The number of characters to consume.
608 *If set to a negative value, the function will consume all the occurences
609 *of a_char found.
610 *After return, if the return value equals CR_OK, this variable contains
611 *the number of characters actually consumed.
612 *@return CR_OK if at least one character has been consumed, an error code
613 *otherwise.
614 */
615 enum CRStatus
616 cr_input_consume_chars (CRInput * a_this, guint32 a_char, gulong * a_nb_char)
617 {
618 enum CRStatus status = CR_OK;
619 gulong nb_consumed = 0;
621 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char,
622 CR_BAD_PARAM_ERROR);
624 g_return_val_if_fail (a_char != 0 || a_nb_char != NULL,
625 CR_BAD_PARAM_ERROR);
627 for (nb_consumed = 0; ((status == CR_OK)
628 && (*a_nb_char > 0
629 && nb_consumed < *a_nb_char));
630 nb_consumed++) {
631 status = cr_input_consume_char (a_this, a_char);
632 }
634 *a_nb_char = nb_consumed;
636 if ((nb_consumed > 0)
637 && ((status == CR_PARSING_ERROR)
638 || (status == CR_END_OF_INPUT_ERROR))) {
639 status = CR_OK;
640 }
642 return status;
643 }
645 /**
646 *Same as cr_input_consume_chars() but this one consumes white
647 *spaces.
648 *
649 *@param a_this the "this pointer" of the current instance of #CRInput.
650 *@param a_nb_chars in/out parameter. The number of white spaces to
651 *consume. After return, holds the number of white spaces actually consumed.
652 *@return CR_OK upon successful completion, an error code otherwise.
653 */
654 enum CRStatus
655 cr_input_consume_white_spaces (CRInput * a_this, gulong * a_nb_chars)
656 {
657 enum CRStatus status = CR_OK;
658 guint32 cur_char = 0,
659 nb_consumed = 0;
661 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_chars,
662 CR_BAD_PARAM_ERROR);
664 for (nb_consumed = 0;
665 ((*a_nb_chars > 0) && (nb_consumed < *a_nb_chars));
666 nb_consumed++) {
667 status = cr_input_peek_char (a_this, &cur_char);
668 if (status != CR_OK)
669 break;
671 /*if the next char is a white space, consume it ! */
672 if (cr_utils_is_white_space (cur_char) == TRUE) {
673 status = cr_input_read_char (a_this, &cur_char);
674 if (status != CR_OK)
675 break;
676 continue;
677 }
679 break;
681 }
683 if (nb_consumed && status == CR_END_OF_INPUT_ERROR) {
684 status = CR_OK;
685 }
687 return status;
688 }
690 /**
691 *Same as cr_input_read_char() but does not update the
692 *internal state of the input stream. The next call
693 *to cr_input_peek_char() or cr_input_read_char() will thus
694 *return the same character as the current one.
695 *@param a_this the current instance of #CRInput.
696 *@param a_char out parameter. The returned character.
697 *@return CR_OK upon successful completion, an error code
698 *otherwise.
699 */
700 enum CRStatus
701 cr_input_peek_char (CRInput * a_this, guint32 * a_char)
702 {
703 enum CRStatus status = CR_OK;
704 glong consumed = 0,
705 nb_bytes_left = 0;
707 g_return_val_if_fail (a_this && PRIVATE (a_this)
708 && a_char, CR_BAD_PARAM_ERROR);
710 if (PRIVATE (a_this)->next_byte_index >=
711 PRIVATE (a_this)->in_buf_size) {
712 return CR_END_OF_INPUT_ERROR;
713 }
715 nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
717 if (nb_bytes_left < 1) {
718 return CR_END_OF_INPUT_ERROR;
719 }
721 status = cr_utils_read_char_from_utf8_buf
722 (PRIVATE (a_this)->in_buf +
723 PRIVATE (a_this)->next_byte_index,
724 nb_bytes_left, a_char, (gulong *)&consumed);
726 return status;
727 }
729 /**
730 *Gets a byte from the input stream,
731 *starting from the current position in the input stream.
732 *Unlike cr_input_peek_next_byte() this method
733 *does not update the state of the current input stream.
734 *Subsequent calls to cr_input_peek_byte with the same arguments
735 *will return the same byte.
736 *
737 *@param a_this the current instance of #CRInput.
738 *@param a_origin the origin to consider in the calculation
739 *of the position of the byte to peek.
740 *@param a_offset the offset of the byte to peek, starting from
741 *the origin specified by a_origin.
742 *@param a_byte out parameter the peeked byte.
743 *@return CR_OK upon successful completion or,
744 *
745 *<ul>
746 *<li>CR_BAD_PARAM_ERROR if at least one of the parameters is invalid</li>
747 *<li>CR_OUT_OF_BOUNDS_ERROR if the indexed byte is out of bounds</li>
748 *</ul>
749 */
750 enum CRStatus
751 cr_input_peek_byte (CRInput * a_this, enum CRSeekPos a_origin,
752 gulong a_offset, guchar * a_byte)
753 {
754 gulong abs_offset = 0;
756 g_return_val_if_fail (a_this && PRIVATE (a_this)
757 && a_byte, CR_BAD_PARAM_ERROR);
759 switch (a_origin) {
761 case CR_SEEK_CUR:
762 abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_offset;
763 break;
765 case CR_SEEK_BEGIN:
766 abs_offset = a_offset;
767 break;
769 case CR_SEEK_END:
770 abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_offset;
771 break;
773 default:
774 return CR_BAD_PARAM_ERROR;
775 }
777 if (abs_offset < PRIVATE (a_this)->in_buf_size) {
779 *a_byte = PRIVATE (a_this)->in_buf[abs_offset];
781 return CR_OK;
783 } else {
784 return CR_END_OF_INPUT_ERROR;
785 }
786 }
788 /**
789 *Same as cr_input_peek_byte() but with a simplified
790 *interface.
791 *@param a_this the current byte input stream.
792 *@param a_offset the offset of the byte to peek, starting
793 *from the current input position pointer.
794 *@param a_eof out parameter. Is set to true is we reach end of
795 *stream. If set to NULL by the caller, this parameter is not taken
796 *in account.
797 *@return the read byte or 0 if something bad happened.
798 */
799 guchar
800 cr_input_peek_byte2 (CRInput * a_this, gulong a_offset, gboolean * a_eof)
801 {
802 guchar result = 0;
803 enum CRStatus status = CR_ERROR;
805 g_return_val_if_fail (a_this && PRIVATE (a_this), 0);
807 if (a_eof)
808 *a_eof = FALSE;
810 status = cr_input_peek_byte (a_this, CR_SEEK_CUR, a_offset, &result);
812 if ((status == CR_END_OF_INPUT_ERROR)
813 && a_eof)
814 *a_eof = TRUE;
816 return result;
817 }
819 /**
820 *Returns the memory address of the byte located at a given offset
821 *in the input stream.
822 *@param a_this the current instance of #CRInput.
823 *@param a_offset the offset of the byte in the input stream starting
824 *from the beginning of the stream.
825 *@return the address, otherwise NULL if an error occured.
826 */
827 guchar *
828 cr_input_get_byte_addr (CRInput * a_this, gulong a_offset)
829 {
830 g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
832 if (a_offset >= PRIVATE (a_this)->nb_bytes) {
833 return NULL;
834 }
836 return &PRIVATE (a_this)->in_buf[a_offset];
837 }
839 /**
840 *Returns the address of the current character pointer.
841 *@param a_this the current input stream
842 *@param a_offset out parameter. The returned address.
843 *@return CR_OK upon successful completion, an error code otherwise.
844 */
845 enum CRStatus
846 cr_input_get_cur_byte_addr (CRInput * a_this, guchar ** a_offset)
847 {
848 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_offset,
849 CR_BAD_PARAM_ERROR);
851 if (!PRIVATE (a_this)->next_byte_index) {
852 return CR_START_OF_INPUT_ERROR;
853 }
855 *a_offset = cr_input_get_byte_addr
856 (a_this, PRIVATE (a_this)->next_byte_index - 1);
858 return CR_OK;
859 }
861 /**
862 *Sets the "current byte index" of the current instance
863 *of #CRInput. Next call to cr_input_get_byte() will return
864 *the byte next after the new "current byte index".
865 *
866 *@param a_this the current instance of #CRInput.
867 *
868 *@param a_origin the origin to consider during the calculation
869 *of the absolute position of the new "current byte index".
870 *
871 *@param a_pos the relative offset of the new "current byte index."
872 *This offset is relative to the origin a_origin.
873 *
874 *@return CR_OK upon successful completion otherwise returns
875 *<ul>
876 *<li>CR_BAD_PARAM_ERROR if at least one of the parameters is not valid</li>
877 *<li>CR_OUT_BOUNDS_ERROR</li>
878 *</ul>
879 */
880 enum CRStatus
881 cr_input_seek_index (CRInput * a_this, enum CRSeekPos a_origin, gint a_pos)
882 {
884 glong abs_offset = 0;
886 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
888 switch (a_origin) {
890 case CR_SEEK_CUR:
891 abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_pos;
892 break;
894 case CR_SEEK_BEGIN:
895 abs_offset = a_pos;
896 break;
898 case CR_SEEK_END:
899 abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_pos;
900 break;
902 default:
903 return CR_BAD_PARAM_ERROR;
904 }
906 if ((abs_offset > 0)
907 && (gulong) abs_offset < PRIVATE (a_this)->nb_bytes) {
909 /*update the input stream's internal state */
910 PRIVATE (a_this)->next_byte_index = abs_offset + 1;
912 return CR_OK;
913 }
915 return CR_OUT_OF_BOUNDS_ERROR;
916 }
918 /**
919 *Gets the position of the "current byte index" which
920 *is basically the position of the last returned byte in the
921 *input stream.
922 *
923 *@param a_this the current instance of #CRInput.
924 *
925 *@param a_pos out parameter. The returned position.
926 *
927 *@return CR_OK upon successful completion. Otherwise,
928 *<ul>
929 *<li>CR_BAD_PARAMETER_ERROR if at least one of the arguments is invalid.</li>
930 *<li>CR_START_OF_INPUT if no call to either cr_input_read_byte()
931 *or cr_input_seek_index() have been issued before calling
932 *cr_input_get_cur_pos()</li>
933 *</ul>
934 *Note that the out parameters of this function are valid if and only if this
935 *function returns CR_OK.
936 */
937 enum CRStatus
938 cr_input_get_cur_pos (CRInput * a_this, CRInputPos * a_pos)
939 {
940 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
941 CR_BAD_PARAM_ERROR);
943 a_pos->next_byte_index = PRIVATE (a_this)->next_byte_index;
944 a_pos->line = PRIVATE (a_this)->line;
945 a_pos->col = PRIVATE (a_this)->col;
946 a_pos->end_of_line = PRIVATE (a_this)->end_of_line;
947 a_pos->end_of_file = PRIVATE (a_this)->end_of_input;
949 return CR_OK;
950 }
952 /**
953 *Gets the current parsing location.
954 *The Parsing location is a public datastructure that
955 *represents the current line/column/byte offset/ in the input
956 *stream.
957 *@param a_this the current instance of #CRInput
958 *@param a_loc the set parsing location.
959 *@return CR_OK upon successful completion, an error
960 *code otherwise.
961 */
962 enum CRStatus
963 cr_input_get_parsing_location (CRInput *a_this,
964 CRParsingLocation *a_loc)
965 {
966 g_return_val_if_fail (a_this
967 && PRIVATE (a_this)
968 && a_loc,
969 CR_BAD_PARAM_ERROR) ;
971 a_loc->line = PRIVATE (a_this)->line ;
972 a_loc->column = PRIVATE (a_this)->col ;
973 if (PRIVATE (a_this)->next_byte_index) {
974 a_loc->byte_offset = PRIVATE (a_this)->next_byte_index - 1 ;
975 } else {
976 a_loc->byte_offset = PRIVATE (a_this)->next_byte_index ;
977 }
978 return CR_OK ;
979 }
981 /**
982 *Getter of the next byte index.
983 *It actually returns the index of the
984 *next byte to be read.
985 *@param a_this the "this pointer" of the current instance of
986 *#CRInput
987 *@param a_index out parameter. The returned index.
988 *@return CR_OK upon successful completion, an error code
989 *otherwise.
990 */
991 enum CRStatus
992 cr_input_get_cur_index (CRInput * a_this, glong * a_index)
993 {
994 g_return_val_if_fail (a_this && PRIVATE (a_this)
995 && a_index, CR_BAD_PARAM_ERROR);
997 *a_index = PRIVATE (a_this)->next_byte_index;
999 return CR_OK;
1000 }
1002 /**
1003 *Setter of the next byte index.
1004 *It sets the index of the next byte to be read.
1005 *@param a_this the "this pointer" of the current instance
1006 *of #CRInput .
1007 *@param a_index the new index to set.
1008 *@return CR_OK upon successful completion, an error code otherwise.
1009 */
1010 enum CRStatus
1011 cr_input_set_cur_index (CRInput * a_this, glong a_index)
1012 {
1013 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1015 PRIVATE (a_this)->next_byte_index = a_index;
1017 return CR_OK;
1018 }
1020 /**
1021 *Sets the end of file flag.
1022 *@param a_this the current instance of #CRInput.
1023 *@param a_eof the new end of file flag.
1024 *@return CR_OK upon successful completion, an error code otherwise.
1025 */
1026 enum CRStatus
1027 cr_input_set_end_of_file (CRInput * a_this, gboolean a_eof)
1028 {
1029 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1031 PRIVATE (a_this)->end_of_input = a_eof;
1033 return CR_OK;
1034 }
1036 /**
1037 *Gets the end of file flag.
1038 *@param a_this the current instance of #CRInput.
1039 *@param a_eof out parameter the place to put the end of
1040 *file flag.
1041 *@return CR_OK upon successful completion, an error code otherwise.
1042 */
1043 enum CRStatus
1044 cr_input_get_end_of_file (CRInput * a_this, gboolean * a_eof)
1045 {
1046 g_return_val_if_fail (a_this && PRIVATE (a_this)
1047 && a_eof, CR_BAD_PARAM_ERROR);
1049 *a_eof = PRIVATE (a_this)->end_of_input;
1051 return CR_OK;
1052 }
1054 /**
1055 *Sets the end of line flag.
1056 *@param a_this the current instance of #CRInput.
1057 *@param a_eol the new end of line flag.
1058 *@return CR_OK upon successful completion, an error code
1059 *otherwise.
1060 */
1061 enum CRStatus
1062 cr_input_set_end_of_line (CRInput * a_this, gboolean a_eol)
1063 {
1064 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1066 PRIVATE (a_this)->end_of_line = a_eol;
1068 return CR_OK;
1069 }
1071 /**
1072 *Gets the end of line flag of the current input.
1073 *@param a_this the current instance of #CRInput
1074 *@param a_eol out parameter. The place to put
1075 *the returned flag
1076 *@return CR_OK upon successful completion, an error code
1077 *otherwise.
1078 */
1079 enum CRStatus
1080 cr_input_get_end_of_line (CRInput * a_this, gboolean * a_eol)
1081 {
1082 g_return_val_if_fail (a_this && PRIVATE (a_this)
1083 && a_eol, CR_BAD_PARAM_ERROR);
1085 *a_eol = PRIVATE (a_this)->end_of_line;
1087 return CR_OK;
1088 }
1090 /**
1091 *Sets the current position in the input stream.
1092 *
1093 *@param a_this the "this pointer" of the current instance of
1094 *#CRInput.
1095 *@param a_pos the new position.
1096 */
1097 enum CRStatus
1098 cr_input_set_cur_pos (CRInput * a_this, CRInputPos * a_pos)
1099 {
1100 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
1101 CR_BAD_PARAM_ERROR);
1103 cr_input_set_column_num (a_this, a_pos->col);
1104 cr_input_set_line_num (a_this, a_pos->line);
1105 cr_input_set_cur_index (a_this, a_pos->next_byte_index);
1106 cr_input_set_end_of_line (a_this, a_pos->end_of_line);
1107 cr_input_set_end_of_file (a_this, a_pos->end_of_file);
1109 return CR_OK;
1110 }