"Initial commit to Gerrit"
[profile/ivi/libcroco.git] / src / cr-input.c
1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8-*- */
2
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  */
23
24 #include "stdio.h"
25 #include <string.h>
26 #include "cr-input.h"
27 #include "cr-enc-handler.h"
28
29 /**
30  *@CRInput:
31  *
32  *The definition of the #CRInput class.
33  */
34
35 /*******************
36  *Private type defs
37  *******************/
38
39 /**
40  *The private attributes of
41  *the #CRInputPriv class.
42  */
43 struct _CRInputPriv {
44         /*
45          *The input buffer
46          */
47         guchar *in_buf;
48         gulong in_buf_size;
49
50         gulong nb_bytes;
51
52         /*
53          *The index of the next byte
54          *to be read.
55          */
56         gulong next_byte_index;
57
58         /*
59          *The current line number
60          */
61         gulong line;
62
63         /*
64          *The current col number
65          */
66         gulong col;
67
68         gboolean end_of_line;
69         gboolean end_of_input;
70
71         /*
72          *the reference count of this
73          *instance.
74          */
75         guint ref_count;
76         gboolean free_in_buf;
77 };
78
79 #define PRIVATE(object) (object)->priv
80
81 /***************************
82  *private constants
83  **************************/
84 #define CR_INPUT_MEM_CHUNK_SIZE 1024 * 4
85
86 static CRInput *cr_input_new_real (void);
87
88 static CRInput *
89 cr_input_new_real (void)
90 {
91         CRInput *result = NULL;
92
93         result = g_try_malloc (sizeof (CRInput));
94         if (!result) {
95                 cr_utils_trace_info ("Out of memory");
96                 return NULL;
97         }
98         memset (result, 0, sizeof (CRInput));
99
100         PRIVATE (result) = g_try_malloc (sizeof (CRInputPriv));
101         if (!PRIVATE (result)) {
102                 cr_utils_trace_info ("Out of memory");
103                 g_free (result);
104                 return NULL;
105         }
106         memset (PRIVATE (result), 0, sizeof (CRInputPriv));
107         PRIVATE (result)->free_in_buf = TRUE;
108         return result;
109 }
110
111 /****************
112  *Public methods
113  ***************/
114
115 /**
116  * cr_input_new_from_buf:
117  *@a_buf: the memory buffer to create the input stream from.
118  *The #CRInput keeps this pointer so user should not free it !.
119  *@a_len: the size of the input buffer.
120  *@a_enc: the buffer's encoding.
121  *@a_free_buf: if set to TRUE, this a_buf will be freed
122  *at the destruction of this instance. If set to false, it is up
123  *to the caller to free it.
124  *
125  *Creates a new input stream from a memory buffer.
126  *Returns the newly built instance of #CRInput.
127  */
128 CRInput *
129 cr_input_new_from_buf (guchar * a_buf,
130                        gulong a_len,
131                        enum CREncoding a_enc,
132                        gboolean a_free_buf)
133 {
134         CRInput *result = NULL;
135         enum CRStatus status = CR_OK;
136         CREncHandler *enc_handler = NULL;
137         gulong len = a_len;
138
139         g_return_val_if_fail (a_buf, NULL);
140
141         result = cr_input_new_real ();
142         g_return_val_if_fail (result, NULL);
143
144         /*transform the encoding in utf8 */
145         if (a_enc != CR_UTF_8) {
146                 enc_handler = cr_enc_handler_get_instance (a_enc);
147                 if (!enc_handler) {
148                         goto error;
149                 }
150
151                 status = cr_enc_handler_convert_input
152                         (enc_handler, a_buf, &len,
153                          &PRIVATE (result)->in_buf,
154                          &PRIVATE (result)->in_buf_size);
155                 if (status != CR_OK)
156                         goto error;
157                 PRIVATE (result)->free_in_buf = TRUE;
158                 if (a_free_buf == TRUE && a_buf) {
159                         g_free (a_buf) ;
160                         a_buf = NULL ;
161                 }                
162                 PRIVATE (result)->nb_bytes = PRIVATE (result)->in_buf_size;
163         } else {
164                 PRIVATE (result)->in_buf = (guchar *) a_buf;
165                 PRIVATE (result)->in_buf_size = a_len;
166                 PRIVATE (result)->nb_bytes = a_len;
167                 PRIVATE (result)->free_in_buf = a_free_buf;
168         }
169         PRIVATE (result)->line = 1;
170         PRIVATE (result)->col =  0;
171         return result;
172
173  error:
174         if (result) {
175                 cr_input_destroy (result);
176                 result = NULL;
177         }
178
179         return NULL;
180 }
181
182 /**
183  * cr_input_new_from_uri:
184  *@a_file_uri: the file to create *the input stream from.
185  *@a_enc: the encoding of the file *to create the input from.
186  *
187  *Creates a new input stream from
188  *a file.
189  *
190  *Returns the newly created input stream if
191  *this method could read the file and create it,
192  *NULL otherwise.
193  */
194
195 CRInput *
196 cr_input_new_from_uri (const gchar * a_file_uri, enum CREncoding a_enc)
197 {
198         CRInput *result = NULL;
199         enum CRStatus status = CR_OK;
200         FILE *file_ptr = NULL;
201         guchar tmp_buf[CR_INPUT_MEM_CHUNK_SIZE] = { 0 };
202         gulong nb_read = 0,
203                 len = 0,
204                 buf_size = 0;
205         gboolean loop = TRUE;
206         guchar *buf = NULL;
207
208         g_return_val_if_fail (a_file_uri, NULL);
209
210         file_ptr = fopen (a_file_uri, "r");
211
212         if (file_ptr == NULL) {
213
214 #ifdef CR_DEBUG
215                 cr_utils_trace_debug ("could not open file");
216 #endif
217                 g_warning ("Could not open file %s\n", a_file_uri);
218
219                 return NULL;
220         }
221
222         /*load the file */
223         while (loop) {
224                 nb_read = fread (tmp_buf, 1 /*read bytes */ ,
225                                  CR_INPUT_MEM_CHUNK_SIZE /*nb of bytes */ ,
226                                  file_ptr);
227
228                 if (nb_read != CR_INPUT_MEM_CHUNK_SIZE) {
229                         /*we read less chars than we wanted */
230                         if (feof (file_ptr)) {
231                                 /*we reached eof */
232                                 loop = FALSE;
233                         } else {
234                                 /*a pb occured !! */
235                                 cr_utils_trace_debug ("an io error occured");
236                                 status = CR_ERROR;
237                                 goto cleanup;
238                         }
239                 }
240
241                 if (status == CR_OK) {
242                         /*read went well */
243                         buf = g_realloc (buf, len + CR_INPUT_MEM_CHUNK_SIZE);
244                         memcpy (buf + len, tmp_buf, nb_read);
245                         len += nb_read;
246                         buf_size += CR_INPUT_MEM_CHUNK_SIZE;
247                 }
248         }
249
250         if (status == CR_OK) {
251                 result = cr_input_new_from_buf (buf, len, a_enc, TRUE);
252                 if (!result) {
253                         goto cleanup;
254                 }
255                 /*
256                  *we should  free buf here because it's own by CRInput.
257                  *(see the last parameter of cr_input_new_from_buf().
258                  */
259                 buf = NULL ;
260         }
261
262  cleanup:
263         if (file_ptr) {
264                 fclose (file_ptr);
265                 file_ptr = NULL;
266         }
267
268         if (buf) {
269                 g_free (buf);
270                 buf = NULL;
271         }
272
273         return result;
274 }
275
276 /**
277  * cr_input_destroy:
278  *@a_this: the current instance of #CRInput.
279  *
280  *The destructor of the #CRInput class.
281  */
282 void
283 cr_input_destroy (CRInput * a_this)
284 {
285         if (a_this == NULL)
286                 return;
287
288         if (PRIVATE (a_this)) {
289                 if (PRIVATE (a_this)->in_buf && PRIVATE (a_this)->free_in_buf) {
290                         g_free (PRIVATE (a_this)->in_buf);
291                         PRIVATE (a_this)->in_buf = NULL;
292                 }
293
294                 g_free (PRIVATE (a_this));
295                 PRIVATE (a_this) = NULL;
296         }
297
298         g_free (a_this);
299 }
300
301 /**
302  * cr_input_ref:
303  *@a_this: the current instance of #CRInput.
304  *
305  *Increments the reference count of the current
306  *instance of #CRInput.
307  */
308 void
309 cr_input_ref (CRInput * a_this)
310 {
311         g_return_if_fail (a_this && PRIVATE (a_this));
312
313         PRIVATE (a_this)->ref_count++;
314 }
315
316 /**
317  * cr_input_unref:
318  *@a_this: the current instance of #CRInput.
319  *
320  *Decrements the reference count of this instance
321  *of #CRInput. If the reference count goes down to
322  *zero, this instance is destroyed.
323  *
324  * Returns TRUE if the instance of #CRInput got destroyed, false otherwise.
325  */
326 gboolean
327 cr_input_unref (CRInput * a_this)
328 {
329         g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);
330
331         if (PRIVATE (a_this)->ref_count) {
332                 PRIVATE (a_this)->ref_count--;
333         }
334
335         if (PRIVATE (a_this)->ref_count == 0) {
336                 cr_input_destroy (a_this);
337                 return TRUE;
338         }
339         return FALSE;
340 }
341
342 /**
343  * cr_input_end_of_input:
344  *@a_this: the current instance of #CRInput.
345  *@a_end_of_input: out parameter. Is set to TRUE if
346  *the current instance has reached the end of its input buffer,
347  *FALSE otherwise.
348  *
349  *Tests wether the current instance of
350  *#CRInput has reached its input buffer.
351  *
352  * Returns CR_OK upon successful completion, an error code otherwise.
353  * Note that all the out parameters of this method are valid if
354  * and only if this method returns CR_OK.
355  */
356 enum CRStatus
357 cr_input_end_of_input (CRInput const * a_this, gboolean * a_end_of_input)
358 {
359         g_return_val_if_fail (a_this && PRIVATE (a_this)
360                               && a_end_of_input, CR_BAD_PARAM_ERROR);
361
362         *a_end_of_input = (PRIVATE (a_this)->next_byte_index
363                            >= PRIVATE (a_this)->in_buf_size) ? TRUE : FALSE;
364
365         return CR_OK;
366 }
367
368 /**
369  * cr_input_get_nb_bytes_left:
370  *@a_this: the current instance of #CRInput.
371  *
372  *Returns the number of bytes left in the input stream
373  *before the end, -1 in case of error.
374  */
375 glong
376 cr_input_get_nb_bytes_left (CRInput const * a_this)
377 {
378         g_return_val_if_fail (a_this && PRIVATE (a_this), -1);
379         g_return_val_if_fail (PRIVATE (a_this)->nb_bytes
380                               <= PRIVATE (a_this)->in_buf_size, -1);
381         g_return_val_if_fail (PRIVATE (a_this)->next_byte_index
382                               <= PRIVATE (a_this)->nb_bytes, -1);
383
384         if (PRIVATE (a_this)->end_of_input)
385                 return 0;
386
387         return PRIVATE (a_this)->nb_bytes - PRIVATE (a_this)->next_byte_index;
388 }
389
390 /**
391  * cr_input_read_byte:
392  *@a_this: the current instance of #CRInput.
393  *@a_byte: out parameter the returned byte.
394  *
395  *Gets the next byte of the input.
396  *Updates the state of the input so that
397  *the next invocation of this method  returns
398  *the next coming byte.
399  *
400  *Returns CR_OK upon successful completion, an error code
401  *otherwise. All the out parameters of this method are valid if
402  *and only if this method returns CR_OK.
403  */
404 enum CRStatus
405 cr_input_read_byte (CRInput * a_this, guchar * a_byte)
406 {
407         g_return_val_if_fail (a_this && PRIVATE (a_this)
408                               && a_byte, CR_BAD_PARAM_ERROR);
409
410         g_return_val_if_fail (PRIVATE (a_this)->next_byte_index <=
411                               PRIVATE (a_this)->nb_bytes, CR_BAD_PARAM_ERROR);
412
413         if (PRIVATE (a_this)->end_of_input == TRUE)
414                 return CR_END_OF_INPUT_ERROR;
415
416         *a_byte = PRIVATE (a_this)->in_buf[PRIVATE (a_this)->next_byte_index];
417
418         if (PRIVATE (a_this)->nb_bytes -
419             PRIVATE (a_this)->next_byte_index < 2) {
420                 PRIVATE (a_this)->end_of_input = TRUE;
421         } else {
422                 PRIVATE (a_this)->next_byte_index++;
423         }
424
425         return CR_OK;
426 }
427
428 /**
429  * cr_input_read_char:
430  *@a_this: the current instance of CRInput.
431  *@a_char: out parameter. The read character.
432  *
433  *Reads an unicode character from the current instance of
434  *#CRInput.
435  *
436  *Returns CR_OK upon successful completion, an error code
437  *otherwise.
438  */
439 enum CRStatus
440 cr_input_read_char (CRInput * a_this, guint32 * a_char)
441 {
442         enum CRStatus status = CR_OK;
443         gulong consumed = 0,
444                 nb_bytes_left = 0;
445
446         g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
447                               CR_BAD_PARAM_ERROR);
448
449         if (PRIVATE (a_this)->end_of_input == TRUE)
450                 return CR_END_OF_INPUT_ERROR;
451
452         nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
453
454         if (nb_bytes_left < 1) {
455                 return CR_END_OF_INPUT_ERROR;
456         }
457
458         status = cr_utils_read_char_from_utf8_buf
459                 (PRIVATE (a_this)->in_buf
460                  +
461                  PRIVATE (a_this)->next_byte_index,
462                  nb_bytes_left, a_char, &consumed);
463
464         if (status == CR_OK) {
465                 /*update next byte index */
466                 PRIVATE (a_this)->next_byte_index += consumed;
467
468                 /*update line and column number */
469                 if (PRIVATE (a_this)->end_of_line == TRUE) {
470                         PRIVATE (a_this)->col = 1;
471                         PRIVATE (a_this)->line++;
472                         PRIVATE (a_this)->end_of_line = FALSE;
473                 } else if (*a_char != '\n') {
474                         PRIVATE (a_this)->col++;
475                 }
476
477                 if (*a_char == '\n') {
478                         PRIVATE (a_this)->end_of_line = TRUE;
479                 }
480
481         }
482
483         return status;
484 }
485
486 /**
487  * cr_input_set_line_num:
488  *@a_this: the "this pointer" of the current instance of #CRInput.
489  *@a_line_num: the new line number.
490  *
491  *Setter of the current line number.
492  *
493  *Return CR_OK upon successful completion, an error code otherwise.
494  */
495 enum CRStatus
496 cr_input_set_line_num (CRInput * a_this, glong a_line_num)
497 {
498         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
499
500         PRIVATE (a_this)->line = a_line_num;
501
502         return CR_OK;
503 }
504
505 /**
506  * cr_input_get_line_num:
507  *@a_this: the "this pointer" of the current instance of #CRInput.
508  *@a_line_num: the returned line number.
509  *
510  *Getter of the current line number.
511  *
512  *Returns CR_OK upon successful completion, an error code otherwise.
513  */
514 enum CRStatus
515 cr_input_get_line_num (CRInput const * a_this, glong * a_line_num)
516 {
517         g_return_val_if_fail (a_this && PRIVATE (a_this)
518                               && a_line_num, CR_BAD_PARAM_ERROR);
519
520         *a_line_num = PRIVATE (a_this)->line;
521
522         return CR_OK;
523 }
524
525 /**
526  * cr_input_set_column_num:
527  *@a_this: the "this pointer" of the current instance of #CRInput.
528  *@a_col: the new column number.
529  *
530  *Setter of the current column number.
531  *
532  *Returns CR_OK upon successful completion, an error code otherwise.
533  */
534 enum CRStatus
535 cr_input_set_column_num (CRInput * a_this, glong a_col)
536 {
537         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
538
539         PRIVATE (a_this)->col = a_col;
540
541         return CR_OK;
542 }
543
544 /**
545  * cr_input_get_column_num:
546  *@a_this: the "this pointer" of the current instance of #CRInput.
547  *@a_col: out parameter
548  *
549  *Getter of the current column number.
550  *
551  *Returns CR_OK upon successful completion, an error code otherwise.
552  */
553 enum CRStatus
554 cr_input_get_column_num (CRInput const * a_this, glong * a_col)
555 {
556         g_return_val_if_fail (a_this && PRIVATE (a_this) && a_col,
557                               CR_BAD_PARAM_ERROR);
558
559         *a_col = PRIVATE (a_this)->col;
560
561         return CR_OK;
562 }
563
564 /**
565  * cr_input_increment_line_num:
566  *@a_this: the "this pointer" of the current instance of #CRInput.
567  *@a_increment: the increment to add to the line number.
568  *
569  *Increments the current line number.
570  *
571  *Returns CR_OK upon successful completion, an error code otherwise.
572  */
573 enum CRStatus
574 cr_input_increment_line_num (CRInput * a_this, glong a_increment)
575 {
576         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
577
578         PRIVATE (a_this)->line += a_increment;
579
580         return CR_OK;
581 }
582
583 /**
584  * cr_input_increment_col_num:
585  *@a_this: the "this pointer" of the current instance of #CRInput.
586  *@a_increment: the increment to add to the column number.
587  *
588  *Increments the current column number.
589  *
590  *Returns CR_OK upon successful completion, an error code otherwise.
591  */
592 enum CRStatus
593 cr_input_increment_col_num (CRInput * a_this, glong a_increment)
594 {
595         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
596
597         PRIVATE (a_this)->col += a_increment;
598
599         return CR_OK;
600 }
601
602 /**
603  * cr_input_consume_char:
604  *@a_this: the this pointer.
605  *@a_char: the character to consume. If set to zero,
606  *consumes any character.
607  *
608  *Consumes the next character of the input stream if
609  *and only if that character equals a_char.
610  *
611  *Returns CR_OK upon successful completion, CR_PARSING_ERROR if
612  *next char is different from a_char, an other error code otherwise
613  */
614 enum CRStatus
615 cr_input_consume_char (CRInput * a_this, guint32 a_char)
616 {
617         guint32 c;
618         enum CRStatus status;
619
620         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
621
622         if ((status = cr_input_peek_char (a_this, &c)) != CR_OK) {
623                 return status;
624         }
625
626         if (c == a_char || a_char == 0) {
627                 status = cr_input_read_char (a_this, &c);
628         } else {
629                 return CR_PARSING_ERROR;
630         }
631
632         return status;
633 }
634
635 /**
636  * cr_input_consume_chars:
637  *@a_this: the this pointer of the current instance of #CRInput.
638  *@a_char: the character to consume.
639  *@a_nb_char: in/out parameter. The number of characters to consume.
640  *If set to a negative value, the function will consume all the occurences
641  *of a_char found.
642  *After return, if the return value equals CR_OK, this variable contains 
643  *the number of characters actually consumed.
644  *
645  *Consumes up to a_nb_char occurences of the next contiguous characters 
646  *which equal a_char. Note that the next character of the input stream
647  **MUST* equal a_char to trigger the consumption, or else, the error
648  *code CR_PARSING_ERROR is returned.
649  *If the number of contiguous characters that equals a_char is less than
650  *a_nb_char, then this function consumes all the characters it can consume.
651  * 
652  *Returns CR_OK if at least one character has been consumed, an error code
653  *otherwise.
654  */
655 enum CRStatus
656 cr_input_consume_chars (CRInput * a_this, guint32 a_char, gulong * a_nb_char)
657 {
658         enum CRStatus status = CR_OK;
659         gulong nb_consumed = 0;
660
661         g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char,
662                               CR_BAD_PARAM_ERROR);
663
664         g_return_val_if_fail (a_char != 0 || a_nb_char != NULL,
665                               CR_BAD_PARAM_ERROR);
666
667         for (nb_consumed = 0; ((status == CR_OK)
668                                && (*a_nb_char > 0
669                                    && nb_consumed < *a_nb_char));
670              nb_consumed++) {
671                 status = cr_input_consume_char (a_this, a_char);
672         }
673
674         *a_nb_char = nb_consumed;
675
676         if ((nb_consumed > 0)
677             && ((status == CR_PARSING_ERROR)
678                 || (status == CR_END_OF_INPUT_ERROR))) {
679                 status = CR_OK;
680         }
681
682         return status;
683 }
684
685 /**
686  * cr_input_consume_white_spaces:
687  *@a_this: the "this pointer" of the current instance of #CRInput.
688  *@a_nb_chars: in/out parameter. The number of white spaces to
689  *consume. After return, holds the number of white spaces actually consumed.
690  *
691  *Same as cr_input_consume_chars() but this one consumes white
692  *spaces.
693  *
694  *Returns CR_OK upon successful completion, an error code otherwise.
695  */
696 enum CRStatus
697 cr_input_consume_white_spaces (CRInput * a_this, gulong * a_nb_chars)
698 {
699         enum CRStatus status = CR_OK;
700         guint32 cur_char = 0,
701                 nb_consumed = 0;
702
703         g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_chars,
704                               CR_BAD_PARAM_ERROR);
705
706         for (nb_consumed = 0;
707              ((*a_nb_chars > 0) && (nb_consumed < *a_nb_chars));
708              nb_consumed++) {
709                 status = cr_input_peek_char (a_this, &cur_char);
710                 if (status != CR_OK)
711                         break;
712
713                 /*if the next char is a white space, consume it ! */
714                 if (cr_utils_is_white_space (cur_char) == TRUE) {
715                         status = cr_input_read_char (a_this, &cur_char);
716                         if (status != CR_OK)
717                                 break;
718                         continue;
719                 }
720
721                 break;
722
723         }
724
725         if (nb_consumed && status == CR_END_OF_INPUT_ERROR) {
726                 status = CR_OK;
727         }
728
729         return status;
730 }
731
732 /**
733  * cr_input_peek_char:
734  *@a_this: the current instance of #CRInput.
735  *@a_char: out parameter. The returned character.
736  *
737  *Same as cr_input_read_char() but does not update the
738  *internal state of the input stream. The next call
739  *to cr_input_peek_char() or cr_input_read_char() will thus
740  *return the same character as the current one.
741  *
742  *Returns CR_OK upon successful completion, an error code
743  *otherwise.
744  */
745 enum CRStatus
746 cr_input_peek_char (CRInput const * a_this, guint32 * a_char)
747 {
748         enum CRStatus status = CR_OK;
749         glong consumed = 0,
750                 nb_bytes_left = 0;
751
752         g_return_val_if_fail (a_this && PRIVATE (a_this)
753                               && a_char, CR_BAD_PARAM_ERROR);
754
755         if (PRIVATE (a_this)->next_byte_index >=
756             PRIVATE (a_this)->in_buf_size) {
757                 return CR_END_OF_INPUT_ERROR;
758         }
759
760         nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
761
762         if (nb_bytes_left < 1) {
763                 return CR_END_OF_INPUT_ERROR;
764         }
765
766         status = cr_utils_read_char_from_utf8_buf
767                 (PRIVATE (a_this)->in_buf +
768                  PRIVATE (a_this)->next_byte_index,
769                  nb_bytes_left, a_char, &consumed);
770
771         return status;
772 }
773
774 /**
775  * cr_input_peek_byte:
776  *@a_this: the current instance of #CRInput.
777  *@a_origin: the origin to consider in the calculation
778  *of the position of the byte to peek.
779  *@a_offset: the offset of the byte to peek, starting from
780  *the origin specified by a_origin.
781  *@a_byte: out parameter the peeked byte.
782  *
783  *Gets a byte from the input stream,
784  *starting from the current position in the input stream.
785  *Unlike cr_input_peek_next_byte() this method
786  *does not update the state of the current input stream.
787  *Subsequent calls to cr_input_peek_byte with the same arguments
788  *will return the same byte.
789  *
790  *Returns CR_OK upon successful completion or,
791  *CR_BAD_PARAM_ERROR if at least one of the parameters is invalid;
792  *CR_OUT_OF_BOUNDS_ERROR if the indexed byte is out of bounds.
793  */
794 enum CRStatus
795 cr_input_peek_byte (CRInput const * a_this, enum CRSeekPos a_origin,
796                     gulong a_offset, guchar * a_byte)
797 {
798         gulong abs_offset = 0;
799
800         g_return_val_if_fail (a_this && PRIVATE (a_this)
801                               && a_byte, CR_BAD_PARAM_ERROR);
802
803         switch (a_origin) {
804
805         case CR_SEEK_CUR:
806                 abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_offset;
807                 break;
808
809         case CR_SEEK_BEGIN:
810                 abs_offset = a_offset;
811                 break;
812
813         case CR_SEEK_END:
814                 abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_offset;
815                 break;
816
817         default:
818                 return CR_BAD_PARAM_ERROR;
819         }
820
821         if (abs_offset < PRIVATE (a_this)->in_buf_size) {
822
823                 *a_byte = PRIVATE (a_this)->in_buf[abs_offset];
824
825                 return CR_OK;
826
827         } else {
828                 return CR_END_OF_INPUT_ERROR;
829         }
830 }
831
832 /**
833  * cr_input_peek_byte2:
834  *@a_this: the current byte input stream.
835  *@a_offset: the offset of the byte to peek, starting
836  *from the current input position pointer.
837  *@a_eof: out parameter. Is set to true is we reach end of
838  *stream. If set to NULL by the caller, this parameter is not taken
839  *in account.
840  *
841  *Same as cr_input_peek_byte() but with a simplified
842  *interface.
843  *
844  *Returns the read byte or 0 if something bad happened.
845  */
846 guchar
847 cr_input_peek_byte2 (CRInput const * a_this, gulong a_offset, gboolean * a_eof)
848 {
849         guchar result = 0;
850         enum CRStatus status = CR_ERROR;
851
852         g_return_val_if_fail (a_this && PRIVATE (a_this), 0);
853
854         if (a_eof)
855                 *a_eof = FALSE;
856
857         status = cr_input_peek_byte (a_this, CR_SEEK_CUR, a_offset, &result);
858
859         if ((status == CR_END_OF_INPUT_ERROR)
860             && a_eof)
861                 *a_eof = TRUE;
862
863         return result;
864 }
865
866 /**
867  * cr_input_get_byte_addr:
868  *@a_this: the current instance of #CRInput.
869  *@a_offset: the offset of the byte in the input stream starting
870  *from the beginning of the stream.
871  *
872  *Gets the memory address of the byte located at a given offset
873  *in the input stream.
874  *
875  *Returns the address, otherwise NULL if an error occured.
876  */
877 guchar *
878 cr_input_get_byte_addr (CRInput * a_this, gulong a_offset)
879 {
880         g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
881
882         if (a_offset >= PRIVATE (a_this)->nb_bytes) {
883                 return NULL;
884         }
885
886         return &PRIVATE (a_this)->in_buf[a_offset];
887 }
888
889 /**
890  * cr_input_get_cur_byte_addr:
891  *@a_this: the current input stream
892  *@a_offset: out parameter. The returned address.
893  *
894  *Gets the address of the current character pointer.
895  *
896  *Returns CR_OK upon successful completion, an error code otherwise.
897  */
898 enum CRStatus
899 cr_input_get_cur_byte_addr (CRInput * a_this, guchar ** a_offset)
900 {
901         g_return_val_if_fail (a_this && PRIVATE (a_this) && a_offset,
902                               CR_BAD_PARAM_ERROR);
903
904         if (!PRIVATE (a_this)->next_byte_index) {
905                 return CR_START_OF_INPUT_ERROR;
906         }
907
908         *a_offset = cr_input_get_byte_addr
909                 (a_this, PRIVATE (a_this)->next_byte_index - 1);
910
911         return CR_OK;
912 }
913
914 /**
915  * cr_input_seek_index:
916  *@a_this: the current instance of #CRInput.
917  *@a_origin: the origin to consider during the calculation
918  *of the absolute position of the new "current byte index".
919  *@a_pos: the relative offset of the new "current byte index."
920  *This offset is relative to the origin a_origin.
921  *
922  *Sets the "current byte index" of the current instance
923  *of #CRInput. Next call to cr_input_get_byte() will return
924  *the byte next after the new "current byte index".
925  *
926  *Returns CR_OK upon successful completion otherwise returns
927  *CR_BAD_PARAM_ERROR if at least one of the parameters is not valid
928  *or CR_OUT_BOUNDS_ERROR in case of error.
929  */
930 enum CRStatus
931 cr_input_seek_index (CRInput * a_this, enum CRSeekPos a_origin, gint a_pos)
932 {
933
934         glong abs_offset = 0;
935
936         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
937
938         switch (a_origin) {
939
940         case CR_SEEK_CUR:
941                 abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_pos;
942                 break;
943
944         case CR_SEEK_BEGIN:
945                 abs_offset = a_pos;
946                 break;
947
948         case CR_SEEK_END:
949                 abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_pos;
950                 break;
951
952         default:
953                 return CR_BAD_PARAM_ERROR;
954         }
955
956         if ((abs_offset > 0)
957             && (gulong) abs_offset < PRIVATE (a_this)->nb_bytes) {
958
959                 /*update the input stream's internal state */
960                 PRIVATE (a_this)->next_byte_index = abs_offset + 1;
961
962                 return CR_OK;
963         }
964
965         return CR_OUT_OF_BOUNDS_ERROR;
966 }
967
968 /**
969  * cr_input_get_cur_pos:
970  *@a_this: the current instance of #CRInput.
971  *@a_pos: out parameter. The returned position.
972  *
973  *Gets the position of the "current byte index" which
974  *is basically the position of the last returned byte in the
975  *input stream.
976  *
977  *Returns CR_OK upon successful completion. Otherwise,
978  *CR_BAD_PARAMETER_ERROR if at least one of the arguments is invalid.
979  *CR_START_OF_INPUT if no call to either cr_input_read_byte()
980  *or cr_input_seek_index() have been issued before calling 
981  *cr_input_get_cur_pos()
982  *Note that the out parameters of this function are valid if and only if this
983  *function returns CR_OK.
984  */
985 enum CRStatus
986 cr_input_get_cur_pos (CRInput const * a_this, CRInputPos * a_pos)
987 {
988         g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
989                               CR_BAD_PARAM_ERROR);
990
991         a_pos->next_byte_index = PRIVATE (a_this)->next_byte_index;
992         a_pos->line = PRIVATE (a_this)->line;
993         a_pos->col = PRIVATE (a_this)->col;
994         a_pos->end_of_line = PRIVATE (a_this)->end_of_line;
995         a_pos->end_of_file = PRIVATE (a_this)->end_of_input;
996
997         return CR_OK;
998 }
999
1000 /**
1001  * cr_input_get_parsing_location:
1002  *@a_this: the current instance of #CRInput
1003  *@a_loc: the set parsing location.
1004  *
1005  *Gets the current parsing location.
1006  *The Parsing location is a public datastructure that
1007  *represents the current line/column/byte offset/ in the input
1008  *stream.
1009  *
1010  *Returns CR_OK upon successful completion, an error
1011  *code otherwise.
1012  */
1013 enum CRStatus
1014 cr_input_get_parsing_location (CRInput const *a_this,
1015                                CRParsingLocation *a_loc)
1016 {
1017         g_return_val_if_fail (a_this 
1018                               && PRIVATE (a_this)
1019                               && a_loc, 
1020                               CR_BAD_PARAM_ERROR) ;
1021
1022         a_loc->line = PRIVATE (a_this)->line ;
1023         a_loc->column = PRIVATE (a_this)->col ;
1024         if (PRIVATE (a_this)->next_byte_index) {
1025                 a_loc->byte_offset = PRIVATE (a_this)->next_byte_index - 1 ;
1026         } else {
1027                 a_loc->byte_offset = PRIVATE (a_this)->next_byte_index  ;
1028         }
1029         return CR_OK ;
1030 }
1031
1032 /**
1033  * cr_input_get_cur_index:
1034  *@a_this: the "this pointer" of the current instance of
1035  *#CRInput
1036  *@a_index: out parameter. The returned index.
1037  *
1038  *Getter of the next byte index. 
1039  *It actually returns the index of the
1040  *next byte to be read.
1041  *
1042  *Returns CR_OK upon successful completion, an error code
1043  *otherwise.
1044  */
1045 enum CRStatus
1046 cr_input_get_cur_index (CRInput const * a_this, glong * a_index)
1047 {
1048         g_return_val_if_fail (a_this && PRIVATE (a_this)
1049                               && a_index, CR_BAD_PARAM_ERROR);
1050
1051         *a_index = PRIVATE (a_this)->next_byte_index;
1052
1053         return CR_OK;
1054 }
1055
1056 /**
1057  * cr_input_set_cur_index:
1058  *@a_this: the "this pointer" of the current instance
1059  *of #CRInput .
1060  *@a_index: the new index to set.
1061  *
1062  *Setter of the next byte index.
1063  *It sets the index of the next byte to be read.
1064  *
1065  *Returns CR_OK upon successful completion, an error code otherwise.
1066  */
1067 enum CRStatus
1068 cr_input_set_cur_index (CRInput * a_this, glong a_index)
1069 {
1070         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1071
1072         PRIVATE (a_this)->next_byte_index = a_index;
1073
1074         return CR_OK;
1075 }
1076
1077 /**
1078  * cr_input_set_end_of_file:
1079  *@a_this: the current instance of #CRInput.
1080  *@a_eof: the new end of file flag.
1081  *
1082  *Sets the end of file flag.
1083  *
1084  *Returns CR_OK upon successful completion, an error code otherwise.
1085  */
1086 enum CRStatus
1087 cr_input_set_end_of_file (CRInput * a_this, gboolean a_eof)
1088 {
1089         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1090
1091         PRIVATE (a_this)->end_of_input = a_eof;
1092
1093         return CR_OK;
1094 }
1095
1096 /**
1097  * cr_input_get_end_of_file:
1098  *@a_this: the current instance of #CRInput.
1099  *@a_eof: out parameter the place to put the end of
1100  *file flag.
1101  *
1102  *Gets the end of file flag.
1103  *
1104  *Returns CR_OK upon successful completion, an error code otherwise.
1105  */
1106 enum CRStatus
1107 cr_input_get_end_of_file (CRInput const * a_this, gboolean * a_eof)
1108 {
1109         g_return_val_if_fail (a_this && PRIVATE (a_this)
1110                               && a_eof, CR_BAD_PARAM_ERROR);
1111
1112         *a_eof = PRIVATE (a_this)->end_of_input;
1113
1114         return CR_OK;
1115 }
1116
1117 /**
1118  * cr_input_set_end_of_line:
1119  *@a_this: the current instance of #CRInput.
1120  *@a_eol: the new end of line flag.
1121  *
1122  *Sets the end of line flag.
1123  *
1124  *Returns CR_OK upon successful completion, an error code
1125  *otherwise.
1126  */
1127 enum CRStatus
1128 cr_input_set_end_of_line (CRInput * a_this, gboolean a_eol)
1129 {
1130         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1131
1132         PRIVATE (a_this)->end_of_line = a_eol;
1133
1134         return CR_OK;
1135 }
1136
1137 /**
1138  * cr_input_get_end_of_line:
1139  *@a_this: the current instance of #CRInput
1140  *@a_eol: out parameter. The place to put
1141  *the returned flag
1142  *
1143  *Gets the end of line flag of the current input.
1144  *
1145  *Returns CR_OK upon successful completion, an error code
1146  *otherwise.
1147  */
1148 enum CRStatus
1149 cr_input_get_end_of_line (CRInput const * a_this, gboolean * a_eol)
1150 {
1151         g_return_val_if_fail (a_this && PRIVATE (a_this)
1152                               && a_eol, CR_BAD_PARAM_ERROR);
1153
1154         *a_eol = PRIVATE (a_this)->end_of_line;
1155
1156         return CR_OK;
1157 }
1158
1159 /**
1160  * cr_input_set_cur_pos:
1161  *@a_this: the "this pointer" of the current instance of
1162  *#CRInput.
1163  *@a_pos: the new position.
1164  *
1165  *Sets the current position in the input stream.
1166  *
1167  * Returns CR_OK upon successful completion, an error code otherwise.
1168  */
1169 enum CRStatus
1170 cr_input_set_cur_pos (CRInput * a_this, CRInputPos const * a_pos)
1171 {
1172         g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
1173                               CR_BAD_PARAM_ERROR);
1174
1175         cr_input_set_column_num (a_this, a_pos->col);
1176         cr_input_set_line_num (a_this, a_pos->line);
1177         cr_input_set_cur_index (a_this, a_pos->next_byte_index);
1178         cr_input_set_end_of_line (a_this, a_pos->end_of_line);
1179         cr_input_set_end_of_file (a_this, a_pos->end_of_file);
1180
1181         return CR_OK;
1182 }