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-2023 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 A68 (chars_in_tty_line) = 0;
34 A68 (halt_typing) = A68_FALSE;
35 change_masks (TOP_NODE (&A68_JOB), BREAKPOINT_INTERRUPT_MASK, A68_FALSE);
36 }
37
38 //! @brief Terminate current line on STDOUT.
39
40 void io_close_tty_line (void)
41 {
42 if (A68 (chars_in_tty_line) > 0) {
43 io_write_string (STDOUT_FILENO, NEWLINE_STRING);
44 }
45 }
46
47 //! @brief Get a char from STDIN.
48
49 char get_stdin_char (void)
50 {
51 ssize_t j;
52 char ch[4];
53 errno = 0;
54 j = io_read_conv (STDIN_FILENO, &(ch[0]), 1);
55 ABEND (j < 0, ERROR_ACTION, __func__);
56 return (char) (j == 1 ? ch[0] : EOF_CHAR);
57 }
58
59 //! @brief Read string from STDIN, until NEWLINE_STRING.
60
61 char *read_string_from_tty (char *prompt)
62 {
63 #if defined (HAVE_READLINE)
64 char *line = readline (prompt);
65 if (line != NO_TEXT && (int) strlen (line) > 0) {
66 add_history (line);
67 }
68 bufcpy (A68 (input_line), line, BUFFER_SIZE);
69 A68 (chars_in_tty_line) = (int) strlen (A68 (input_line));
70 a68_free (line);
71 return A68 (input_line);
72
73 #else
74 int ch, k = 0, n;
75 if (prompt != NO_TEXT) {
76 io_close_tty_line ();
77 io_write_string (STDOUT_FILENO, prompt);
78 }
79 ch = get_stdin_char ();
80 while (ch != NEWLINE_CHAR && k < BUFFER_SIZE - 1) {
81 if (ch == EOF_CHAR) {
82 A68 (input_line)[0] = EOF_CHAR;
83 A68 (input_line)[1] = NULL_CHAR;
84 A68 (chars_in_tty_line) = 1;
85 return A68 (input_line);
86 } else {
87 A68 (input_line)[k++] = (char) ch;
88 ch = get_stdin_char ();
89 }
90 }
91 A68 (input_line)[k] = NULL_CHAR;
92 n = (int) strlen (A68 (input_line));
93 A68 (chars_in_tty_line) = (ch == NEWLINE_CHAR ? 0 : (n > 0 ? n : 1));
94 return A68 (input_line);
95 #endif
96 }
97
98 //! @brief Write string to file.
99
100 void io_write_string (FILE_T f, const char *z)
101 {
102 ssize_t j;
103 errno = 0;
104 if (f != STDOUT_FILENO && f != STDERR_FILENO) {
105 // Writing to file.
106 j = io_write_conv (f, z, strlen (z));
107 ABEND (j < 0, ERROR_ACTION, __func__);
108 } else {
109 // Writing to TTY.
110 int first, k;
111 // Write parts until end-of-string.
112 first = 0;
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 j = io_write_conv (f, &(z[first]), (size_t) n);
123 ABEND (j < 0, ERROR_ACTION, __func__);
124 A68 (chars_in_tty_line) += n;
125 }
126 if (z[k] == NEWLINE_CHAR) {
127 // Pretty-print newline.
128 k++;
129 first = k;
130 j = io_write_conv (f, NEWLINE_STRING, 1);
131 ABEND (j < 0, ERROR_ACTION, __func__);
132 A68 (chars_in_tty_line) = 0;
133 }
134 } while (z[k] != NULL_CHAR);
135 }
136 }
137
138 //! @brief Read bytes from file into buffer.
139
140 ssize_t io_read (FILE_T fd, void *buf, size_t n)
141 {
142 size_t to_do = n;
143 int restarts = 0;
144 char *z = (char *) buf;
145 while (to_do > 0) {
146 #if defined (BUILD_WIN32)
147 int bytes_read;
148 #else
149 ssize_t bytes_read;
150 #endif
151 errno = 0;
152 bytes_read = read (fd, z, to_do);
153 if (bytes_read < 0) {
154 if (errno == EINTR) {
155 // interrupt, retry.
156 bytes_read = 0;
157 if (restarts++ > MAX_RESTART) {
158 return -1;
159 }
160 } else {
161 // read error.
162 return -1;
163 }
164 } else if (bytes_read == 0) {
165 break; // EOF_CHAR
166 }
167 to_do -= (size_t) bytes_read;
168 z += bytes_read;
169 }
170 return (ssize_t) n - (ssize_t) to_do; // return >= 0
171 }
172
173 //! @brief Writes n bytes from buffer to file.
174
175 ssize_t io_write (FILE_T fd, const void *buf, size_t n)
176 {
177 size_t to_do = n;
178 int restarts = 0;
179 char *z = (char *) buf;
180 while (to_do > 0) {
181 ssize_t bytes_written;
182 errno = 0;
183 bytes_written = write (fd, z, to_do);
184 if (bytes_written <= 0) {
185 if (errno == EINTR) {
186 // interrupt, retry.
187 bytes_written = 0;
188 if (restarts++ > MAX_RESTART) {
189 return -1;
190 }
191 } else {
192 // write error.
193 return -1;
194 }
195 }
196 to_do -= (size_t) bytes_written;
197 z += bytes_written;
198 }
199 return (ssize_t) n;
200 }
201
202 //! @brief Read bytes from file into buffer.
203
204 ssize_t io_read_conv (FILE_T fd, void *buf, size_t n)
205 {
206 size_t to_do = n;
207 int restarts = 0;
208 char *z = (char *) buf;
209 while (to_do > 0) {
210 #if defined (BUILD_WIN32)
211 int bytes_read;
212 #else
213 ssize_t bytes_read;
214 #endif
215 errno = 0;
216 bytes_read = read (fd, z, to_do);
217 if (bytes_read < 0) {
218 if (errno == EINTR) {
219 // interrupt, retry.
220 bytes_read = 0;
221 if (restarts++ > MAX_RESTART) {
222 return -1;
223 }
224 } else {
225 // read error.
226 return -1;
227 }
228 } else if (bytes_read == 0) {
229 break; // EOF_CHAR
230 }
231 to_do -= (size_t) bytes_read;
232 z += bytes_read;
233 }
234 return (ssize_t) n - (ssize_t) to_do;
235 }
236
237 //! @brief Writes n bytes from buffer to file.
238
239 ssize_t io_write_conv (FILE_T fd, const void *buf, size_t n)
240 {
241 size_t to_do = n;
242 int restarts = 0;
243 char *z = (char *) buf;
244 while (to_do > 0) {
245 ssize_t bytes_written;
246 errno = 0;
247 bytes_written = write (fd, z, to_do);
248 if (bytes_written <= 0) {
249 if (errno == EINTR) {
250 // interrupt, retry.
251 bytes_written = 0;
252 if (restarts++ > MAX_RESTART) {
253 return -1;
254 }
255 } else {
256 // write error.
257 return -1;
258 }
259 }
260 to_do -= (size_t) bytes_written;
261 z += bytes_written;
262 }
263 return (ssize_t) n;
264 }