1// This file is part of SmallBASIC
2//
3// SmallBASIC streams (normal files), driver
4//
5// This program is distributed under the terms of the GPL v2.0 or later
6// Download the GNU Public License (GPL) from www.gnu.org
7//
8// Copyright(C) 2000 Nicholas Christopoulos
9
10#include "common/sys.h"
11#include "common/device.h"
12#include "common/pproc.h"
13
14#include <errno.h>
15
16#if defined(_UnixOS)
17#include <sys/time.h>
18#include <unistd.h>
19#endif
20#include <dirent.h>
21
22#if !defined(O_BINARY)
23#define O_BINARY 0
24#endif
25
26#include "common/fs_stream.h"
27
28/*
29 * open a file
30 */
31int stream_open(dev_file_t *f) {
32 int osflags, osshare;
33
34 if (f->open_flags == DEV_FILE_OUTPUT) {
35 remove(f->name);
36 }
37
38 if (f->open_flags & DEV_FILE_EXCL) {
39 osshare = 0;
40 } else {
41 osshare = S_IRUSR;
42 }
43
44 // take care not to set any write flags when simply reading a file.
45 // the file may be open in another program (such as excel) which has
46 // a write lock on the file causing the bas program to needlessly fail.
47 osflags = (O_RDONLY | O_BINARY);
48
49 if (f->open_flags & DEV_FILE_OUTPUT) {
50 osflags |= (O_CREAT | O_WRONLY);
51 osshare |= S_IWUSR;
52 }
53 if (f->open_flags & DEV_FILE_APPEND) {
54 osflags |= (O_CREAT | O_APPEND | O_WRONLY);
55 osshare |= S_IWUSR;
56 }
57
58#if defined(_UnixOS)
59 if (strcmp(f->name, "SDIN:") == 0) {
60 f->handle = 0;
61 }
62 else if (strcmp(f->name, "SOUT:") == 0) {
63 f->handle = 1;
64 }
65 else if (strcmp(f->name, "SERR:") == 0) {
66 f->handle = 2;
67 }
68 else {
69 f->handle = open(f->name, osflags, osshare);
70 if (f->handle < 0 && gsb_bas_dir[0]) {
71 char file[OS_PATHNAME_SIZE];
72 strlcpy(file, gsb_bas_dir, sizeof(file));
73 strlcat(file, f->name, sizeof(file));
74 f->handle = open(file, osflags, osshare);
75 }
76 }
77#else
78 f->handle = open(f->name, osflags);
79#endif
80
81 if (f->handle < 0) {
82 err_file((f->last_error = errno));
83 }
84 return (f->handle >= 0);
85}
86
87/*
88 * close the stream
89 */
90int stream_close(dev_file_t *f) {
91 int r;
92
93 r = close(f->handle);
94 f->handle = -1;
95 if (r) {
96 err_file((f->last_error = errno));
97 }
98 return (r == 0);
99}
100
101/*
102 */
103int stream_write(dev_file_t *f, byte *data, uint32_t size) {
104 int r;
105
106 r = write(f->handle, data, size);
107 if (r != (int) size) {
108 err_file((f->last_error = errno));
109 }
110 return (r == (int) size);
111}
112
113/*
114 */
115int stream_read(dev_file_t *f, byte *data, uint32_t size) {
116 int r;
117
118 r = read(f->handle, data, size);
119 if (r != (int) size) {
120 err_file((f->last_error = errno));
121 }
122 return (r == (int) size);
123}
124
125/*
126 * returns the current position
127 */
128uint32_t stream_tell(dev_file_t *f) {
129 return lseek(f->handle, 0, SEEK_CUR);
130}
131
132/*
133 * returns the file-length
134 */
135uint32_t stream_length(dev_file_t *f) {
136 long pos, endpos;
137
138 pos = lseek(f->handle, 0, SEEK_CUR);
139 if (pos != -1) {
140 endpos = lseek(f->handle, 0, SEEK_END);
141 lseek(f->handle, pos, SEEK_SET);
142 return endpos;
143 } else {
144 err_file((f->last_error = errno));
145 }
146 return 0;
147}
148
149/*
150 */
151uint32_t stream_seek(dev_file_t *f, uint32_t offset) {
152 return lseek(f->handle, offset, SEEK_SET);
153}
154
155/*
156 */
157int stream_eof(dev_file_t *f) {
158 long pos, endpos;
159
160 pos = lseek(f->handle, 0, SEEK_CUR);
161 if (pos != -1) {
162 endpos = lseek(f->handle, 0, SEEK_END);
163 lseek(f->handle, pos, SEEK_SET);
164 return (pos == endpos);
165 } else {
166 err_file((f->last_error = errno));
167 }
168 return 1;
169}
170