Line data Source code
1 : /******************************************************************************
2 : * Nickel - a library for hierarchical maps and .ini files
3 : * One of the Bohr Game Libraries (see chaoslizard.org/devel/bohr)
4 : * Copyright (C) 2008 Charles Lindsay. Some rights reserved; see COPYING.
5 : * $Id: buf.c 332 2008-01-13 18:32:02Z chaz $
6 : ******************************************************************************/
7 :
8 :
9 : #include "internal.h"
10 : #include <bohr/ni.h>
11 :
12 : #include <assert.h>
13 : #include <errno.h>
14 : #include <stdio.h>
15 : #include <stdlib.h>
16 : #include <string.h>
17 :
18 :
19 : // How big to make the internal buffer when it's created.
20 : #define INITIAL_BUF_SIZE 4096
21 :
22 :
23 : /* Initializes the file_buf.
24 : */
25 103 : elektraNi_PRIVATE int InitFileBuf (file_buf * restrict b, FILE * restrict f)
26 : {
27 103 : *b = (file_buf) FILE_BUF_INIT;
28 103 : b->stream = f;
29 206 : return Ds_InitVector_uc (&b->buffer, INITIAL_BUF_SIZE);
30 : }
31 :
32 : /* Frees memory associated with the file_buf.
33 : */
34 103 : elektraNi_PRIVATE void FreeFileBuf (file_buf * restrict b)
35 : {
36 206 : Ds_FreeVector_uc (&b->buffer);
37 103 : *b = (file_buf) FILE_BUF_INIT;
38 103 : }
39 :
40 : /* Basically like fgetc on our file_buf. Translates newlines automatically for
41 : * us. Returns EOF if error or the file is done.
42 : */
43 33938 : elektraNi_PRIVATE int BufGetC (file_buf * restrict b)
44 : {
45 : int c;
46 :
47 33938 : if (b->pos >= b->buffer.num && !feof (b->stream))
48 : {
49 : // We need more data and can pull it.
50 :
51 33911 : if (b->buffer.num + 2 <= b->buffer.cap || Ds_ResizeVector_uc (&b->buffer, b->buffer.cap << 1))
52 : {
53 : // We now have space, possibly as a result of just expanding.
54 :
55 : // Get a char; if it's not eof, set next char in buffer to it.
56 33911 : if ((c = fgetc (b->stream)) != EOF)
57 : {
58 33808 : if ((b->buffer.buf[b->buffer.num++] = c) == '\r')
59 : {
60 : // Translate \r or \r\n to just \n.
61 :
62 0 : b->buffer.buf[b->buffer.num - 1] = '\n';
63 :
64 : // Get the next one and ignore it if it's \n.
65 0 : if ((c = fgetc (b->stream)) != '\n' && c != EOF) b->buffer.buf[b->buffer.num++] = c;
66 : }
67 : }
68 : }
69 : }
70 :
71 : // Return the current character and advance the position pointer.
72 33938 : c = (b->pos < b->buffer.num ? b->buffer.buf[b->pos] : EOF);
73 33938 : b->pos++;
74 33938 : return c;
75 : }
76 :
77 : /* Basically like fseek(b, -n_back, SEEK_CUR). It undoes n_back BufGetC()
78 : * calls, regardless of whether BufGetC() returned EOF.
79 : */
80 25 : elektraNi_PRIVATE void BufSeekBack (file_buf * restrict b, size_t n_back)
81 : {
82 : assert (b->pos >= n_back);
83 :
84 25 : b->pos -= n_back;
85 25 : }
86 :
87 : /* Flushes the internal buffer without affecting the stream position. This
88 : * lets us keep the memory footprint down.
89 : */
90 3110 : elektraNi_PRIVATE void BufFlush (file_buf * restrict b)
91 : {
92 3110 : b->pos = 0;
93 3110 : b->buffer.num = 0;
94 3110 : }
|