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