summaryrefslogtreecommitdiff
path: root/rushs/tinyprintf/tinylibstream/include/libstream.h
blob: 459432d2b53b433eb462feec47bc633745c081f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#ifndef LIBSTREAM_H
#define LIBSTREAM_H

#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <unistd.h>

/*
** /!\ DO NOT MODIFY THIS FILE, AS IT WILL BE OVERRIDDEN DURING CORRECTION. /!\
**
** You can add your own functions declarations to OTHER HEADER FILES.
*/

/* the value returned when end of file is reached */
#define LBS_EOF (-1)

/* the size of the buffer */
#define LBS_BUFFER_SIZE 32

/*
** Describes the current operation:
**  - if reading, the buffer contains read-buffered data
**  - if writing, the buffer contains write-buffered data
*/
enum stream_io_operation
{
    STREAM_READING = 0,
    STREAM_WRITING,
};

/*
** Controls when to flush the buffer:
**  - when unbuffered, flush every time a character is written
**  - when buffered, flush when the buffer is full
**  - when line buffered, flush when the buffer is full or when a \n
**    character is written
*/
enum stream_buffering
{
    STREAM_UNBUFFERED = 0,
    STREAM_LINE_BUFFERED,
    STREAM_BUFFERED,
};

struct stream
{
    /* the flags passed to open */
    int flags;

    /*
    ** Initially, this variable is 0.
    ** When a function such as fgetc fails, it is set to 1 to indicate
    ** something went wrong. This is useful to make the difference between
    ** reaching the end of file and read errors while using fgetc and
    ** some others.
    ** It is often referred to as the error indicator.
    */
    int error;

    /* the file descriptor, as returned by open(2) */
    int fd;

    /*
    ** the kind of data stored by the buffer.
    ** The default value shouldn't matter.
    */
    enum stream_io_operation io_operation;

    /*
    ** defines when to flush **output**.
    ** This field does not control input buffering (which is always fully
    ** buffered).
    **
    ** The default value is LINE_BUFFERED if isatty(fd), BUFFERED otherwise.
    */
    enum stream_buffering buffering_mode;

    /* the amount of used bytes in the buffer */
    size_t buffered_size;

    /*
    ** /!\ This field only makes sense when io_operation is STREAM_READING /!\
    ** the amount of data already read from the buffer by the user.
    */
    size_t already_read;

    /*
    **                   buffer
    **               -------------->
    ** +==============+====================+---------------------+
    ** | already_read | remaining_buffered | unused_buffer_space |
    ** +==============+====================+---------------------+
    **   \_______________________________/
    **             buffered_size
    **
    ** /!\ The buffer can contain either read-buffered or write-buffered data,
    **     depending on the value of io_operation /!\
    */
    char buffer[LBS_BUFFER_SIZE];
};

/*
** These functions are defined in a header for optimization reasons:
** each .c file that includes this header will get its own copy of the
** function's code, thus easily make optimizations.
**
** ``static`` means each compilation unit (.c file) will have its own copy
** of the function without them clashing.
**
** ``inline`` means the content of the function should be "copy pasted"
** where it's called. It also tells the compiler not to complain when the
** function isn't used.
**
** They're just like a macro, except the type of arguments is checked.
*/

static inline size_t stream_remaining_buffered(struct stream *stream)
{
    return stream->buffered_size - stream->already_read;
}

static inline size_t stream_unused_buffer_space(struct stream *stream)
{
    return sizeof(stream->buffer) - stream->buffered_size;
}

static inline bool stream_readable(struct stream *stream)
{
    int access_mode = stream->flags & O_ACCMODE;
    if (access_mode == O_RDWR)
        return true;
    return access_mode == O_RDONLY;
}

static inline bool stream_writable(struct stream *stream)
{
    int access_mode = stream->flags & O_ACCMODE;
    if (access_mode == O_RDWR)
        return true;
    return access_mode == O_WRONLY;
}

static inline int lbs_ferror(struct stream *stream)
{
    return stream->error;
}

static inline void lbs_clearerr(struct stream *stream)
{
    stream->error = 0;
}

static inline void lbs_setbufmode(struct stream *stream,
                                  enum stream_buffering mode)
{
    stream->buffering_mode = mode;
}

struct stream *lbs_fopen(const char *path, const char *mode);
struct stream *lbs_fdopen(int fd, const char *mode);
int lbs_fflush(struct stream *stream);
int lbs_fclose(struct stream *stream);
int lbs_fputc(int c, struct stream *stream);
int lbs_fgetc(struct stream *stream);

#endif /* !LIBSTREAM_H */