home · contact · privacy
Moved textfile_sizes() to readwrite library.
[plomrogue] / src / readwrite.c
1 /* readwrite.c */
2
3 #include "readwrite.h"
4 #include <stdio.h> /* for FILE typedef, fgetc(), fputc(), fseek() */
5 #include <stdint.h> /* for uint8_t, uint16_t, uint32_t */
6
7
8
9 /* Read/write "x" from/to "file" as bigendian representation of "size" bits. On
10  * failure, return 1, else 0. (As of of now, all extern read/write functions
11  * build on top of these.)
12  *
13  * Only use multiples of 8 greater or equal 32 for "size", so that storage
14  * inside uint32_t is possible. Originally a bit number check prefaced the code
15  * of both functions. It was removed as redundant due to all possible "size"
16  * values being hardcoded into the library (i.e. in all extern functions calling
17  * / wrapping around either function). If this ever changes, (re-)insert:
18  *
19  *    if (0 == size || size > 32 || 0 != size % 8)
20  *    {
21  *        return 1;
22  *    }
23  */
24 static uint8_t read_uintX_bigendian(FILE * file, uint32_t * x, uint8_t size);
25 static uint8_t write_uintX_bigendian(FILE * file, uint32_t x, uint8_t size);
26
27
28
29 extern uint8_t textfile_sizes(FILE * file, uint16_t * linemax_p,
30                               uint16_t * n_lines_p)
31 {
32     int c = 0;
33     uint16_t c_count = 0;
34     uint16_t n_lines = 0;
35     uint16_t linemax = 0;
36     while (1)
37     {
38         c = fgetc(file);
39         if (EOF == c)
40         {
41             break;
42         }
43         c_count++;
44         if ('\n' == c)
45         {
46             if (c_count > linemax)
47             {
48                 linemax = c_count;
49             }
50             c_count = 0;
51             if (n_lines_p)
52             {
53                 n_lines++;
54             }
55         }
56     }
57     if (0 == linemax && 0 < c_count) /* Handle files that consist of only one */
58     {                                /* line / lack newline chars.            */
59         linemax = c_count;
60     }
61
62     if (-1 == fseek(file, 0, SEEK_SET))
63     {
64         return 1;
65     }
66     * linemax_p = linemax;
67     if (n_lines_p)
68     {
69         * n_lines_p = n_lines;
70     }
71     return 0;
72 }
73
74
75
76 static uint8_t read_uintX_bigendian(FILE * file, uint32_t * x, uint8_t size)
77 {
78     * x = 0;
79     int16_t bitshift = size - 8;
80     int test;
81     for (; bitshift >= 0; bitshift = bitshift - 8)
82     {
83         test = fgetc(file);
84         if (EOF == test)
85         {
86             return 1;
87         }
88         * x = * x + ((uint32_t) test << bitshift);
89     }
90     return 0;
91 }
92
93
94
95 static uint8_t write_uintX_bigendian(FILE * file, uint32_t x, uint8_t size)
96 {
97     int16_t bitshift = size - 8;
98     for (; bitshift >= 0; bitshift = bitshift - 8)
99     {
100         if (EOF == fputc((x >> bitshift) & 0xFF, file))
101         {
102             return 1;
103         }
104     }
105     return 0;
106 }
107
108
109
110 extern uint8_t read_uint8(FILE * file, uint8_t * x)
111 {
112     /* Since read_uintX_bigendian() works on -- and zeroes -- four bytes, direct
113      * work on values of fewer bytes would corrupt immediate neighbor values.
114      */
115     uint32_t y = * x;
116     uint8_t err = read_uintX_bigendian(file, &y, 8);
117     * x = (uint8_t) y;
118     return err;
119 }
120
121
122
123 extern uint8_t read_uint16_bigendian(FILE * file, uint16_t * x)
124 {
125     /* See read_uint8() introductory code comment for rationale. */
126     uint32_t y = * x;
127     uint8_t err = read_uintX_bigendian(file, &y, 16);
128     * x = (uint16_t) y;
129     return err;
130 }
131
132
133
134 extern uint8_t read_uint32_bigendian(FILE * file, uint32_t * x)
135 {
136     return read_uintX_bigendian(file, x, 32);
137 }
138
139
140
141 extern uint8_t write_uint8(uint8_t x, FILE * file)
142 {
143     return write_uintX_bigendian(file, x, 8);
144 }
145
146
147
148 extern uint8_t write_uint16_bigendian(uint16_t x, FILE * file)
149 {
150     return write_uintX_bigendian(file, x, 16);
151 }
152
153
154
155 extern uint8_t write_uint32_bigendian(uint32_t x, FILE * file)
156 {
157     return write_uintX_bigendian(file, x, 32);
158 }