a68g-io.c
1 //! @file a68g-io.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2025 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! Low-level input-output routines.
25
26 #include "a68g.h"
27 #include "a68g-prelude.h"
28
29 //! @brief Initialise output to STDOUT.
30
31 void init_tty (void)
32 {
33 A68G (chars_in_stderr) = 0;
34 A68G (chars_in_stdout) = 0;
35 A68G (halt_typing) = A68G_FALSE;
36 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_INTERRUPT_MASK, A68G_FALSE);
37 }
38
39 //! @brief Terminate current line on STDOUT.
40
41 void io_close_tty_line (void)
42 {
43 if (A68G (chars_in_stderr) > 0) {
44 A68G (chars_in_stderr) = 0;
45 io_write_string (A68G_STDERR, NEWLINE_STRING);
46 }
47 if (A68G (chars_in_stdout) > 0) {
48 A68G (chars_in_stdout) = 0;
49 io_write_string (A68G_STDOUT, NEWLINE_STRING);
50 }
51 }
52
53 //! @brief Get a char from STDIN.
54
55 char get_stdin_char (void)
56 {
57 char ch[4];
58 errno = 0;
59 ssize_t j = io_read_conv (A68G_STDIN, &(ch[0]), 1);
60 ABEND (j < 0, ERROR_ACTION, __func__);
61 return (char) (j == 1 ? ch[0] : EOF_CHAR);
62 }
63
64 //! @brief Read string from STDIN, until NEWLINE_STRING.
65
66 char *read_string_from_tty (char *prompt)
67 {
68 #if defined (HAVE_READLINE)
69 char *line = readline (prompt);
70 if (line != NO_TEXT && strlen (line) > 0) {
71 add_history (line);
72 }
73 a68g_bufcpy (A68G (input_line), line, BUFFER_SIZE);
74 A68G (chars_in_stdout) = strlen (A68G (input_line));
75 a68g_free (line);
76 return A68G (input_line);
77 #else
78 if (prompt != NO_TEXT) {
79 io_close_tty_line ();
80 io_write_string (A68G_STDOUT, prompt);
81 }
82 int ch = get_stdin_char (), k= 0;
83 while (ch != NEWLINE_CHAR && k < BUFFER_SIZE - 1) {
84 if (ch == EOF_CHAR) {
85 A68G (input_line)[0] = EOF_CHAR;
86 A68G (input_line)[1] = NULL_CHAR;
87 A68G (chars_in_stdout) = 1;
88 return A68G (input_line);
89 } else {
90 A68G (input_line)[k++] = (char) ch;
91 ch = get_stdin_char ();
92 }
93 }
94 A68G (input_line)[k] = NULL_CHAR;
95 size_t n = strlen (A68G (input_line));
96 A68G (chars_in_stdout) = (ch == NEWLINE_CHAR ? 0 : (n > 0 ? n : 1));
97 return A68G (input_line);
98 #endif
99 }
100
101 //! @brief Write string to file.
102
103 void io_write_string (FILE_T f, const char *z)
104 {
105 errno = 0;
106 if (f != A68G_STDOUT && f != A68G_STDERR) {
107 // Writing to file.
108 ssize_t j = io_write_conv (f, z, strlen (z));
109 ABEND (j < 0, ERROR_ACTION, __func__);
110 } else {
111 // Writing to TTY parts until end-of-string.
112 int first = 0, k;
113 do {
114 k = first;
115 // How far can we get?.
116 while (z[k] != NULL_CHAR && z[k] != NEWLINE_CHAR) {
117 k++;
118 }
119 if (k > first) {
120 // Write these characters.
121 int n = k - first;
122 ssize_t j = io_write_conv (f, &(z[first]), (size_t) n);
123 ABEND (j < 0, ERROR_ACTION, __func__);
124 if (f == A68G_STDERR) {
125 A68G (chars_in_stderr) += n;
126 } else {
127 A68G (chars_in_stdout) += n;
128 }
129 }
130 if (z[k] == NEWLINE_CHAR) {
131 // Pretty-print newline.
132 k++;
133 first = k;
134 ssize_t j = io_write_conv (f, NEWLINE_STRING, 1);
135 ABEND (j < 0, ERROR_ACTION, __func__);
136 if (f == A68G_STDERR) {
137 A68G (chars_in_stderr) = 0;
138 } else {
139 A68G (chars_in_stdout) = 0;
140 }
141 }
142 } while (z[k] != NULL_CHAR);
143 }
144 }
145
146 //! @brief Read bytes from file into buffer.
147
148 ssize_t io_read (FILE_T fd, void *buf, size_t n)
149 {
150 size_t to_do = n;
151 int restarts = 0;
152 char *z = (char *) buf;
153 while (to_do > 0) {
154 #if defined (BUILD_WIN32)
155 int bytes_read;
156 #else
157 ssize_t bytes_read;
158 #endif
159 errno = 0;
160 bytes_read = read (fd, z, to_do);
161 if (bytes_read < 0) {
162 if (errno == EINTR) {
163 // interrupt, retry.
164 bytes_read = 0;
165 if (restarts++ > MAX_RESTART) {
166 return -1;
167 }
168 } else {
169 // read error.
170 return -1;
171 }
172 } else if (bytes_read == 0) {
173 break; // EOF_CHAR
174 }
175 to_do -= (size_t) bytes_read;
176 z += bytes_read;
177 }
178 return (ssize_t) n - (ssize_t) to_do; // return >= 0
179 }
180
181 //! @brief Writes n bytes from buffer to file.
182
183 ssize_t io_write (FILE_T fd, const void *buf, size_t n)
184 {
185 size_t to_do = n;
186 int restarts = 0;
187 char *z = (char *) buf;
188 while (to_do > 0) {
189 ssize_t bytes_written;
190 errno = 0;
191 bytes_written = write (fd, z, to_do);
192 if (bytes_written <= 0) {
193 if (errno == EINTR) {
194 // interrupt, retry.
195 bytes_written = 0;
196 if (restarts++ > MAX_RESTART) {
197 return -1;
198 }
199 } else {
200 // write error.
201 return -1;
202 }
203 }
204 to_do -= (size_t) bytes_written;
205 z += bytes_written;
206 }
207 return (ssize_t) n;
208 }
209
210 //! @brief Read bytes from file into buffer.
211
212 ssize_t io_read_conv (FILE_T fd, void *buf, size_t n)
213 {
214 size_t to_do = n;
215 int restarts = 0;
216 char *z = (char *) buf;
217 while (to_do > 0) {
218 #if defined (BUILD_WIN32)
219 int bytes_read;
220 #else
221 ssize_t bytes_read;
222 #endif
223 errno = 0;
224 bytes_read = read (fd, z, to_do);
225 if (bytes_read < 0) {
226 if (errno == EINTR) {
227 // interrupt, retry.
228 bytes_read = 0;
229 if (restarts++ > MAX_RESTART) {
230 return -1;
231 }
232 } else {
233 // read error.
234 return -1;
235 }
236 } else if (bytes_read == 0) {
237 break; // EOF_CHAR
238 }
239 to_do -= (size_t) bytes_read;
240 z += bytes_read;
241 }
242 return (ssize_t) n - (ssize_t) to_do;
243 }
244
245 //! @brief Writes n bytes from buffer to file.
246
247 ssize_t io_write_conv (FILE_T fd, const void *buf, size_t n)
248 {
249 size_t to_do = n;
250 int restarts = 0;
251 char *z = (char *) buf;
252 while (to_do > 0) {
253 ssize_t bytes_written;
254 errno = 0;
255 bytes_written = write (fd, z, to_do);
256 if (bytes_written <= 0) {
257 if (errno == EINTR) {
258 // interrupt, retry.
259 bytes_written = 0;
260 if (restarts++ > MAX_RESTART) {
261 return -1;
262 }
263 } else {
264 // write error.
265 return -1;
266 }
267 }
268 to_do -= (size_t) bytes_written;
269 z += bytes_written;
270 }
271 return (ssize_t) n;
272 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|