1
2 /*---------------------------------------------------------------------
3 File Handling
4 ---------------------------------------------------------------------*/
5
6
7 /*---------------------------------------------------------------------
8 I keep an array of file handles. RETRO will use the index number as
9 its representation of the file.
10 ---------------------------------------------------------------------*/
11
12 FILE *OpenFileHandles[MAX_OPEN_FILES];
13
14 /*---------------------------------------------------------------------
15 `files_get_handle()` returns a file handle, or 0 if there are no
16 available handle slots in the array.
17 ---------------------------------------------------------------------*/
18
files_get_handle()19 CELL files_get_handle() {
20 CELL i;
21 for(i = 1; i < MAX_OPEN_FILES; i++)
22 if (OpenFileHandles[i] == 0)
23 return i;
24 return 0;
25 }
26
27
28 /*---------------------------------------------------------------------
29 `file_open()` opens a file. This pulls from the RETRO data stack:
30
31 - mode (number, TOS)
32 - filename (string, NOS)
33
34 Modes are:
35
36 | Mode | Corresponds To | Description |
37 | ---- | -------------- | -------------------- |
38 | 0 | rb | Open for reading |
39 | 1 | w | Open for writing |
40 | 2 | a | Open for append |
41 | 3 | rb+ | Open for read/update |
42
43 The file name should be a NULL terminated string. This will attempt
44 to open the requested file and will return a handle (index number
45 into the `OpenFileHandles` array).
46 ---------------------------------------------------------------------*/
47
file_open()48 void file_open() {
49 CELL slot, mode, name;
50 char *request;
51 slot = files_get_handle();
52 mode = stack_pop();
53 name = stack_pop();
54 request = string_extract(name);
55 if (slot > 0) {
56 if (mode == 0) OpenFileHandles[slot] = fopen(request, "rb");
57 if (mode == 1) OpenFileHandles[slot] = fopen(request, "w");
58 if (mode == 2) OpenFileHandles[slot] = fopen(request, "a");
59 if (mode == 3) OpenFileHandles[slot] = fopen(request, "rb+");
60 }
61 if (OpenFileHandles[slot] == NULL) {
62 OpenFileHandles[slot] = 0;
63 slot = 0;
64 }
65 stack_push(slot);
66 }
67
68
69 /*---------------------------------------------------------------------
70 `file_read()` reads a byte from a file. This takes a file pointer
71 from the stack and pushes the character that was read to the stack.
72 ---------------------------------------------------------------------*/
73
file_read()74 void file_read() {
75 CELL c;
76 CELL slot = stack_pop();
77 #ifndef NOCHECKS
78 if (slot <= 0 || slot > MAX_OPEN_FILES || OpenFileHandles[slot] == 0) {
79 printf("\nERROR (nga/file_read): Invalid file handle\n");
80 exit(1);
81 }
82 #endif
83 c = fgetc(OpenFileHandles[slot]);
84 stack_push(feof(OpenFileHandles[slot]) ? 0 : c);
85 }
86
87
88 /*---------------------------------------------------------------------
89 `file_write()` writes a byte to a file. This takes a file pointer
90 (TOS) and a byte (NOS) from the stack. It does not return any values
91 on the stack.
92 ---------------------------------------------------------------------*/
93
file_write()94 void file_write() {
95 CELL slot, c, r;
96 slot = stack_pop();
97 #ifndef NOCHECKS
98 if (slot <= 0 || slot > MAX_OPEN_FILES || OpenFileHandles[slot] == 0) {
99 printf("\nERROR (nga/file_write): Invalid file handle\n");
100 exit(1);
101 }
102 #endif
103 c = stack_pop();
104 r = fputc(c, OpenFileHandles[slot]);
105 }
106
107
108 /*---------------------------------------------------------------------
109 `file_close()` closes a file. This takes a file handle from the
110 stack and does not return anything on the stack.
111 ---------------------------------------------------------------------*/
112
file_close()113 void file_close() {
114 CELL slot = stack_pop();
115 #ifndef NOCHECKS
116 if (slot <= 0 || slot > MAX_OPEN_FILES || OpenFileHandles[slot] == 0) {
117 printf("\nERROR (nga/file_close): Invalid file handle\n");
118 exit(1);
119 }
120 #endif
121 fclose(OpenFileHandles[slot]);
122 OpenFileHandles[slot] = 0;
123 }
124
125
126 /*---------------------------------------------------------------------
127 `file_get_position()` provides the current index into a file. This
128 takes the file handle from the stack and returns the offset.
129 ---------------------------------------------------------------------*/
130
file_get_position()131 void file_get_position() {
132 CELL slot = stack_pop();
133 #ifndef NOCHECKS
134 if (slot <= 0 || slot > MAX_OPEN_FILES || OpenFileHandles[slot] == 0) {
135 printf("\nERROR (nga/file_get_position): Invalid file handle\n");
136 exit(1);
137 }
138 #endif
139 stack_push((CELL) ftell(OpenFileHandles[slot]));
140 }
141
142
143 /*---------------------------------------------------------------------
144 `file_set_position()` changes the current index into a file to the
145 specified one. This takes a file handle (TOS) and new offset (NOS)
146 from the stack.
147 ---------------------------------------------------------------------*/
148
file_set_position()149 void file_set_position() {
150 CELL slot, pos;
151 slot = stack_pop();
152 pos = stack_pop();
153 #ifndef NOCHECKS
154 if (slot <= 0 || slot > MAX_OPEN_FILES || OpenFileHandles[slot] == 0) {
155 printf("\nERROR (nga/file_set_position): Invalid file handle\n");
156 exit(1);
157 }
158 #endif
159 fseek(OpenFileHandles[slot], pos, SEEK_SET);
160 }
161
162
163 /*---------------------------------------------------------------------
164 `file_get_size()` returns the size of a file, or 0 if empty. If the
165 file is a directory, it returns -1. It takes a file handle from the
166 stack.
167 ---------------------------------------------------------------------*/
168
file_get_size()169 void file_get_size() {
170 CELL slot, current, r, size;
171 struct stat buffer;
172 slot = stack_pop();
173 #ifndef NOCHECKS
174 if (slot <= 0 || slot > MAX_OPEN_FILES || OpenFileHandles[slot] == 0) {
175 printf("\nERROR (nga/file_get_size): Invalid file handle\n");
176 exit(1);
177 }
178 #endif
179 fstat(fileno(OpenFileHandles[slot]), &buffer);
180 if (!S_ISDIR(buffer.st_mode)) {
181 current = ftell(OpenFileHandles[slot]);
182 r = fseek(OpenFileHandles[slot], 0, SEEK_END);
183 size = ftell(OpenFileHandles[slot]);
184 fseek(OpenFileHandles[slot], current, SEEK_SET);
185 } else {
186 r = -1;
187 size = 0;
188 }
189 stack_push((r == 0) ? size : 0);
190 }
191
192
193 /*---------------------------------------------------------------------
194 `file_delete()` removes a file. This takes a file name (as a string)
195 from the stack.
196 ---------------------------------------------------------------------*/
197
file_delete()198 void file_delete() {
199 char *request;
200 CELL name = stack_pop();
201 request = string_extract(name);
202 unlink(request);
203 }
204
205
206 /*---------------------------------------------------------------------
207 `file_flush()` flushes any pending writes to disk. This takes a
208 file handle from the stack.
209 ---------------------------------------------------------------------*/
210
file_flush()211 void file_flush() {
212 CELL slot;
213 slot = stack_pop();
214 #ifndef NOCHECKS
215 if (slot <= 0 || slot > MAX_OPEN_FILES || OpenFileHandles[slot] == 0) {
216 printf("\nERROR (nga/file_flush): Invalid file handle\n");
217 exit(1);
218 }
219 #endif
220 fflush(OpenFileHandles[slot]);
221 }
222
223
224 Handler FileActions[10] = {
225 file_open,
226 file_close,
227 file_read,
228 file_write,
229 file_get_position,
230 file_set_position,
231 file_get_size,
232 file_delete,
233 file_flush
234 };
235
io_filesystem_query()236 void io_filesystem_query() {
237 stack_push(0);
238 stack_push(4);
239 }
240
io_filesystem_handler()241 void io_filesystem_handler() {
242 FileActions[stack_pop()]();
243 }
244