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