1 /************************************************************************
2 * This program is Copyright (C) 1986-1996 by Jonathan Payne. JOVE is *
3 * provided to you without charge, and with no warranty. You may give *
4 * away copies of JOVE, including sources, provided that this notice is *
5 * included in all the files. *
6 ************************************************************************/
7
8 #include "jove.h"
9 #include "fp.h"
10 #include "jctype.h"
11 #include "disp.h"
12 #include "fmt.h"
13
14 #ifdef MAC
15 # include "mac.h"
16 #else /* !MAC */
17 # include <sys/stat.h>
18 # ifndef MSFILESYSTEM
19 # include <sys/file.h>
20 # else /* MSFILESYSTEM */
21 # include <fcntl.h>
22 # include <io.h>
23 # endif /* MSFILESYSTEM */
24 #endif /* !MAC */
25
26 #include <errno.h>
27
28 #ifdef RAINBOW
29 private int rbwrite proto((int, char *, int));
30 #endif
31
32 #ifndef L_SET
33 # define L_SET 0
34 #endif
35
36 #define MAXFILES 20 /* good enough for my purposes */
37
38 private File openfiles[MAXFILES]; /* must be zeroed initially */
39
40 File *
fd_open(name,flags,fd,buffer,buf_size)41 fd_open(name, flags, fd, buffer, buf_size)
42 char *name,
43 *buffer;
44 int flags,
45 fd,
46 buf_size;
47 {
48 register File *fp;
49 register int i;
50
51 for (fp = openfiles, i = 0; i < MAXFILES; i++, fp++)
52 if (fp->f_flags == 0)
53 break;
54 if (i == MAXFILES)
55 complain("[Too many open files!]");
56 fp->f_bufsize = buf_size;
57 fp->f_cnt = 0;
58 fp->f_fd = fd;
59 fp->f_flags = flags;
60 if (buffer == NULL) {
61 buffer = emalloc((size_t)buf_size);
62 fp->f_flags |= F_MYBUF;
63 }
64 fp->f_base = fp->f_ptr = buffer;
65 fp->f_name = copystr(name);
66
67 return fp;
68 }
69
70 void
gc_openfiles()71 gc_openfiles()
72 {
73 register File *fp;
74
75 for (fp = openfiles; fp < &openfiles[MAXFILES]; fp++)
76 if (fp->f_flags != 0 && (fp->f_flags & F_LOCKED) == 0)
77 f_close(fp);
78 }
79
80 File *
f_open(name,flags,buffer,buf_size)81 f_open(name, flags, buffer, buf_size)
82 char *name,
83 *buffer;
84 int flags,
85 buf_size;
86 {
87 register int fd;
88
89 switch (F_MODE(flags)) {
90 case F_READ:
91 #ifdef MSFILESYSTEM
92 fd = open(name, O_RDONLY|O_BINARY);
93 #else
94 fd = open(name, 0);
95 #endif
96 break;
97
98 case F_APPEND:
99 #ifdef MSFILESYSTEM
100 fd = open(name, O_WRONLY|O_BINARY);
101 #else
102 fd = open(name, 1);
103 #endif
104 if (fd != -1) {
105 (void) lseek(fd, 0L, 2);
106 break;
107 }
108 /* FALLTHROUGH */
109 case F_WRITE:
110 #ifdef MSFILESYSTEM
111 fd = open(name, O_CREAT|O_TRUNC|O_BINARY|O_RDWR, S_IWRITE|S_IREAD);
112 #else
113 fd = creat(name, CreatMode);
114 #endif
115 break;
116
117 default:
118 fd = -1; /* avoid uninitialized complaint from gcc -W */
119 error("invalid F_MODE");
120 /* NOTREACHED */
121 }
122 if (fd == -1)
123 return NULL;
124 return fd_open(name, flags, fd, buffer, buf_size);
125 }
126
127 void
f_close(fp)128 f_close(fp)
129 File *fp;
130 {
131 if ((fp->f_flags & (F_WRITE|F_APPEND))
132 && (fp->f_flags & F_ERR) == 0)
133 {
134 flushout(fp);
135 #ifdef USE_FSYNC
136 (void) fsync(fp->f_fd);
137 #endif
138 }
139 (void) close(fp->f_fd);
140 if (fp->f_flags & F_MYBUF)
141 free((UnivPtr) fp->f_base);
142 free((UnivPtr) fp->f_name);
143 fp->f_flags = 0; /* indicates that we're available */
144 }
145
146 ZXchar
f_filbuf(fp)147 f_filbuf(fp)
148 File *fp;
149 {
150 if (fp->f_flags & (F_EOF|F_ERR))
151 return EOF;
152 fp->f_ptr = fp->f_base;
153 #ifndef MSDOS
154 do {
155 #endif /* MSDOS */
156 fp->f_cnt = read(fp->f_fd, (UnivPtr) fp->f_base, (size_t) fp->f_bufsize);
157 #ifndef MSDOS
158 } while (fp->f_cnt == -1 && errno == EINTR);
159 #endif /* MSDOS */
160 if (fp->f_cnt == -1) {
161 /* I/O error -- treat as EOF */
162 writef("[Read error: %s]", strerror(errno));
163 fp->f_flags |= F_ERR | F_EOF;
164 return EOF;
165 }
166 if (fp->f_cnt == 0) {
167 fp->f_flags |= F_EOF;
168 return EOF;
169 }
170 io_chars += fp->f_cnt;
171 return f_getc(fp);
172 }
173
174 void
putstr(s)175 putstr(s)
176 register const char *s;
177 {
178 register char c;
179
180 while ((c = *s++) != '\0')
181 scr_putchar(c);
182 }
183
184 void
fputnchar(s,n,fp)185 fputnchar(s, n, fp)
186 register char *s;
187 register int n;
188 register File *fp;
189 {
190 while (--n >= 0)
191 f_putc(*s++, fp);
192 }
193
194 #ifndef NO_JSTDOUT
195 void
flushscreen()196 flushscreen()
197 {
198 flushout(jstdout);
199 }
200 #endif /* !NO_JSTDOUT */
201
202 void
f_seek(fp,offset)203 f_seek(fp, offset)
204 register File *fp;
205 off_t offset;
206 {
207 if (fp->f_flags & (F_WRITE|F_APPEND))
208 flushout(fp);
209 fp->f_cnt = 0; /* next read will f_filbuf(), next write
210 will flush() with no bad effects */
211 lseek(fp->f_fd, (long) offset, L_SET);
212 }
213
214 void
flushout(fp)215 flushout(fp)
216 register File *fp;
217 {
218 if (fp->f_flags & (F_READ | F_STRING | F_ERR)) {
219 if (fp->f_flags != F_STRING)
220 abort(); /* IMPOSSIBLE */
221 /* We just banged into the end of a string.
222 * In the interests of continuing, we will cause
223 * the rest of the output to be be heaped in the
224 * last position. Surely it will end up as a NUL. UGH!
225 */
226 fp->f_cnt = 1;
227 fp->f_ptr = &fp->f_base[fp->f_bufsize - 1];
228 } else {
229 char *p = fp->f_base;
230
231 for (;;) {
232 SSIZE_T
233 n = fp->f_ptr - p,
234 wr;
235
236 if (n <= 0)
237 break;
238 #ifdef RAINBOW
239 wr = rbwrite(fp->f_fd, (UnivPtr) p, (size_t)n);
240 #else
241 wr = write(fp->f_fd, (UnivPtr) p, (size_t)n);
242 #endif
243 if (wr >= 0) {
244 p += wr;
245 } else if (errno != EINTR) {
246 #ifndef NO_JSTDOUT
247 if (fp == jstdout)
248 break; /* bail out, silently */
249 #endif
250 fp->f_flags |= F_ERR;
251 error("[I/O error(%s); file = %s, fd = %d]",
252 strerror(errno), fp->f_name, fp->f_fd);
253 }
254 }
255
256 fp->f_cnt = fp->f_bufsize;
257 fp->f_ptr = fp->f_base;
258 }
259 }
260
261 bool
f_gets(fp,buf,max)262 f_gets(fp, buf, max)
263 register File *fp;
264 char *buf;
265 size_t max;
266 {
267 register char *cp = buf;
268 register ZXchar c;
269 char *endp = buf + max - 1;
270
271 if (fp->f_flags & F_EOF)
272 return YES;
273 while ((c = f_getc(fp)) != EOF && c != EOL) {
274 /* We can't store NUL in our buffer, so ignore it.
275 * Similarly, we can only store characters less than NCHARS.
276 * Of course, with a little ingenuity we could store NUL:
277 * NUL could be represented by EOL.
278 */
279 if (c == '\0'
280 #if NCHARS != UCHAR_ROOF
281 || c >= NCHARS
282 #endif
283 )
284 continue;
285
286 if (cp >= endp) {
287 add_mess(" [Line too long]");
288 rbell();
289 return YES;
290 }
291 *cp++ = c;
292 }
293 *cp = '\0';
294 if (c == EOF) {
295 if (cp != buf)
296 add_mess(" [Incomplete last line]");
297 return YES;
298 }
299 #ifdef USE_CRLF
300 /* a CR followed by a LF is treated as a NL.
301 * Bug: the line-buffer is effectively shortened by one character.
302 */
303 if (cp != buf && cp[-1] == '\r')
304 *--cp = '\0';
305 #endif /* USE_CRLF */
306 io_lines += 1;
307 return NO; /* this means okay */
308 }
309
310 /* skip to beginning of next line, i.e., next read returns first
311 character of new line */
312
313 void
f_toNL(fp)314 f_toNL(fp)
315 register File *fp;
316 {
317 if (fp->f_flags & F_EOF)
318 return;
319 for (;;) {
320 switch (f_getc(fp)) {
321 case EOF:
322 fp->f_flags |= F_EOF;
323 /*FALLTHROUGH*/
324 case EOL:
325 return;
326 }
327 }
328 }
329
330 #ifdef PIPEPROCS
331 size_t
f_readn(fp,addr,n)332 f_readn(fp, addr, n)
333 register File *fp;
334 register char *addr;
335 size_t n;
336 {
337 register size_t nleft;
338
339 for (nleft = n; nleft > 0; nleft--) {
340 ZXchar c = f_getc(fp);
341
342 if (f_eof(fp))
343 break;
344 *addr++ = c;
345 }
346 return n - nleft;
347 }
348 #endif /* PIPEPROCS */
349
350 /* ScrBufSize is the size of the buffer for jstdout. It is also the
351 * number of characters to be output between checks for input, so
352 * it is meaningful even if jstdout isn't used. Its value is set by
353 * settout based on the baud rate of output (on systems with baud rates).
354 */
355 #ifdef NO_JSTDOUT
356 int ScrBufSize = 256;
357 #else
358 int ScrBufSize = 1; /* until settout decides a better value & allocates a buf */
359 #endif
360
361 #ifndef NO_JSTDOUT
362 private char one_buf;
363
364 private File stdout_File = {1, 1, 1, F_WRITE, &one_buf, &one_buf, (char *)NULL};
365 File *jstdout = &stdout_File;
366 #endif
367
368 #ifdef RAINBOW
369
370 /*
371 * use the Rainbow's video output function
372 */
373
374 #include <dos.h>
375
376 private int
rbwrite(fd,buf,cnt)377 rbwrite(fd, buf, cnt)
378 int fd;
379 char *buf;
380 int cnt;
381 {
382 union REGS vr;
383
384 if (fd != 1) {
385 write(fd, buf, cnt);
386 } else {
387 while (cnt-- > 0) {
388 vr.x.ax = *buf++;
389 vr.x.di = 0;
390 int86(0x18, &vr, &vr);
391 }
392 }
393 }
394 #endif /* RAINBOW */
395