commit e5299bb
zzo38
·
2022-11-16 06:15:51 +0000 UTC
parent 5ed07f5
Extended delete/append ports, to add additional functions such as seeking.
3 files changed,
+148,
-53
+58,
-0
1@@ -186,6 +186,9 @@ The vector is called after passing command-line arguments, but before any
2 other events occur. If accepting input from stdin, then it will also be
3 called after all input from stdin has been read.
4
5+The -x switch also changes the meaning of the delete and append ports of
6+the file device. See below about extended file device.
7+
8 (Note: Using this feature will make the program not portable to other
9 implementations, and should be avoided if possible. However, it is
10 available if its functions (e.g. expanded memory) are needed in your
11@@ -193,6 +196,61 @@ program for any reason. Most programs probably will not need expanded
12 memory; some might be able to optionally use it.)
13
14
15+=== Extended file device ===
16+
17+If the -x switch is used, then the delete and append ports of the file
18+device have a different meaning than usual.
19+
20+N.B. Use of these extensions in an implementation which does not support
21+them may cause files to be inadvertently deleted or corrupted. (This
22+implementation will ignore the delete port entirely if the -x switch is
23+not specified.) Furthermore, they may be changed in future; please make
24+a discussion if you have any intention to use these extensions, or even
25+to use the delete/append ports without these extensions. There are some
26+problems with the design of the file device, so I would want to suggest
27+these changes in order to make an improvement. Unfortunately, it is not
28+as simple as other devices, but it may be necessary if file handling is
29+to be working properly.
30+
31+The delete port can be given any of the values:
32+
33+* 0x00 = Does nothing.
34+
35+* 0x01 = Delete the current file. (Not currently implemented.)
36+
37+* 0x10 = Close the file.
38+
39+* 0x11 = Open the file for reading. Success is 1 if opened.
40+
41+* 0x12 = Open the file for writing. Success is 1 if opened.
42+
43+* 0x80 to 0x8F = Seek. Bit0 and bit1 specify how much the length field
44+should be multiplied by, where 0 means zero, 1 means one, 2 means 64K,
45+and 3 is reserved. Bit2 and bit3 indicate where to seek and which way,
46+where 0 means forward from the current position, 1 means backward from
47+the current position, 2 means forward from the beginning, and 3 means
48+backward from the beginning.
49+
50+Telling it to open a file will close it first, even if it is already open
51+in the correct mode. Also, seeking will not work unless the file is already
52+open, so it must first be opened, either by one of the above commands for
53+opening a file or by attempting to read from or write to it.
54+
55+The append port has one of the following values:
56+
57+* 0 = Files opened for writing are truncated.
58+
59+* 1 = Files opened for writing will append at the end of the file.
60+
61+* 2 = Files are opened for both reading and writing. In this case,
62+switching from reading to writing or vice-versa will not close and reopen
63+the file like it does in other cases. If writing is disabled, then this is
64+treated the same as 0.
65+
66+Any value may be bitwise ORed by sixteen to refuse to open a file for
67+writing if the file already exists.
68+
69+
70 === Extension loading ===
71
72 (This section describes a feature which is not implemented yet. Some
M
main.c
+88,
-53
1@@ -150,6 +150,7 @@ static Uint8 use_screen=1;
2 static Uint8 use_mouse=1;
3 static Uint8 use_debug=0;
4 static Uint8 use_utc=0;
5+static Uint8 use_extension=0;
6 static Uint8 hide_cursor=0;
7 static Uint8 allow_write=0;
8 static Uint8 zoom=1;
9@@ -420,6 +421,71 @@ static Uint16 files_stat(char*name,Uint16 len,Uint8*out) {
10 return 0;
11 }
12
13+static void files_seek(UxnFile*uf,Uint8 mode,Uint32 len) {
14+ switch(mode&3) {
15+ case 0: len=0; break;
16+ case 1: /* do nothing */ break;
17+ case 2: len<<=16; break;
18+ case 3: return;
19+ }
20+ switch(uf->mode) {
21+ case 1: case 2: case 4:
22+ switch((mode>>2)&3) {
23+ case 0: fseek(uf->file,len,SEEK_CUR); break;
24+ case 1: fseek(uf->file,-len,SEEK_CUR); break;
25+ case 2: fseek(uf->file,len,SEEK_SET); break;
26+ case 3: fseek(uf->file,-len,SEEK_END); break;
27+ }
28+ break;
29+ }
30+}
31+
32+static int files_set(Device*dev,int rw) {
33+ // rw: 0(close) 1(read) 2(write)
34+ // return: 1 if file opened, 0 if not opened
35+ Uint8 m=dev->d[7];
36+ UxnFile*uf=dev->aux;
37+ if(uf->file) fclose(uf->file);
38+ if(uf->dir) closedir(uf->dir);
39+ uf->file=0;
40+ uf->dir=0;
41+ uf->de=0;
42+ uf->mode=0;
43+ dev->d[2]=dev->d[3]=0;
44+ if(!uf->name[0]) return 0;
45+ if(m && !use_extension) m=1;
46+ if((m&15)==2 && rw && allow_write) {
47+ if(rw==1) m&=15;
48+ if(uf->file=fopen(uf->name,m&16?"w+x":"r+")) {
49+ uf->mode=4;
50+ return 1;
51+ } else if(uf->file=fopen(uf->name,m&16?"w+x":"w+")) {
52+ uf->mode=4;
53+ return 1;
54+ } else {
55+ warn("Cannot open file '%s' for reading and writing",uf->name);
56+ }
57+ } else if(rw==1) {
58+ if(uf->dir=opendir(uf->name)) {
59+ uf->mode=3;
60+ return 1;
61+ } else if(uf->file=fopen(uf->name,"r")) {
62+ uf->mode=1;
63+ return 1;
64+ } else {
65+ warn("Cannot open file '%s' for reading",uf->name);
66+ }
67+ } else if(rw==2 && allow_write) {
68+ if(uf->file=fopen(uf->name,m==1?"a":m==17?"ax":m==16?"wx":"w")) {
69+ uf->mode=2;
70+ return 1;
71+ } else {
72+ warn("Cannot open file '%s' for writing",uf->name);
73+ }
74+ }
75+ return 0;
76+}
77+
78 static void files_out(Device*dev,Uint8 id) {
79 UxnFile*uf=dev->aux;
80 Uint16 len=GET16(dev->d+10);
81@@ -433,15 +499,22 @@ static void files_out(Device*dev,Uint8 id) {
82 y=files_stat(uf->name,len,mem+addr);
83 if(y<=len) PUT16(dev->d+2,y);
84 break;
85+ case 6:
86+ if(!use_extension) break;
87+ dev->d[2]=dev->d[3]=0;
88+ switch(dev->d[6]) {
89+ case 0x10 ... 0x12: // Close/open
90+ if(dev->d[6]==0x12 && !allow_write) goto disallow;
91+ dev->d[3]=files_set(dev,dev->d[6]&0x0F);
92+ break;
93+ case 0x80 ... 0x8F: // Seek
94+ files_seek(uf,dev->d[6]&0x0F,len);
95+ break;
96+ }
97+ break;
98 case 9:
99 addr=GET16(dev->d+8);
100- if(uf->file) fclose(uf->file);
101- if(uf->dir) closedir(uf->dir);
102- uf->file=0;
103- uf->dir=0;
104- uf->de=0;
105- uf->mode=0;
106- dev->d[2]=dev->d[3]=0;
107+ files_set(dev,0);
108 x=GET16(dev->d+8);
109 for(i=0;i<4095;i++) {
110 if(!(uf->name[i]=mem[x+i])) break;
111@@ -453,7 +526,7 @@ static void files_out(Device*dev,Uint8 id) {
112 addr=GET16(dev->d+12);
113 dev->d[2]=dev->d[3]=0;
114 read:
115- if(uf->mode==1) {
116+ if(uf->mode==1 || uf->mode==4) {
117 if(!len) break;
118 x=fread(mem+addr,1,len,uf->file);
119 PUT16(dev->d+2,x);
120@@ -464,32 +537,19 @@ static void files_out(Device*dev,Uint8 id) {
121 } else if(uf->mode==3) {
122 //TODO
123 } else {
124- if(uf->file) fclose(uf->file);
125- if(uf->dir) closedir(uf->dir);
126- uf->file=0;
127- uf->dir=0;
128- uf->de=0;
129- if(!uf->name[0]) break;
130- if(uf->dir=opendir(uf->name)) {
131- uf->mode=3;
132- goto read;
133- } else if(uf->file=fopen(uf->name,"r")) {
134- uf->mode=1;
135- goto read;
136- } else {
137- warn("Cannot open file '%s' for reading",uf->name);
138- }
139+ if(files_set(dev,1)) goto read;
140 }
141 break;
142 case 15:
143 addr=GET16(dev->d+14);
144 dev->d[2]=dev->d[3]=0;
145 if(!allow_write) {
146+ disallow:
147 warnx("Not allowed to write to file '%s'.",uf->name);
148 break;
149 }
150 write:
151- if(uf->mode==2) {
152+ if(uf->mode==2 || uf->mode==4) {
153 if(!len) break;
154 x=fwrite(mem+addr,1,len,uf->file);
155 PUT16(dev->d+2,x);
156@@ -498,18 +558,7 @@ static void files_out(Device*dev,Uint8 id) {
157 clearerr(uf->file);
158 }
159 } else {
160- if(uf->file) fclose(uf->file);
161- if(uf->dir) closedir(uf->dir);
162- uf->file=0;
163- uf->dir=0;
164- uf->de=0;
165- if(!uf->name[0]) break;
166- if(uf->file=fopen(uf->name,dev->d[7]?"a":"w")) {
167- uf->mode=2;
168- goto read;
169- } else {
170- warn("Cannot open file '%s' for %sing",uf->name,dev->d[7]?"append":"writ");
171- }
172+ if(files_set(dev,2)) goto write;
173 }
174 break;
175 }
176@@ -522,7 +571,7 @@ static Uint8 files_in(Device*dev,Uint8 id) {
177 case 12: case 13:
178 dev->d[2]=dev->d[3]=0;
179 read:
180- if(uf->mode==1) {
181+ if(uf->mode==1 || uf->mode==4) {
182 c=fgetc(uf->file);
183 if(c==EOF) {
184 if(ferror(uf->file)) {
185@@ -537,21 +586,7 @@ static Uint8 files_in(Device*dev,Uint8 id) {
186 } else if(uf->mode==3) {
187 return 0;
188 } else {
189- if(uf->file) fclose(uf->file);
190- if(uf->dir) closedir(uf->dir);
191- uf->file=0;
192- uf->dir=0;
193- uf->de=0;
194- if(!uf->name[0]) break;
195- if(uf->name[0]=='.' && !uf->name[1] && (uf->dir=opendir(uf->name))) {
196- uf->mode=3;
197- goto read;
198- } else if(uf->file=fopen(uf->name,"r")) {
199- uf->mode=1;
200- goto read;
201- } else {
202- warn("Cannot open file '%s' for reading",uf->name);
203- }
204+ if(files_set(dev,1)) goto read;
205 }
206 return 0;
207 default: return dev->d[id];
208@@ -974,7 +1009,7 @@ int main(int argc,char**argv) {
209 case 'q': use_console=0; break;
210 case 't': timer_rate=strtol(optarg,0,10); break;
211 case 'w': default_width=strtol(optarg,0,10); break;
212- case 'x': device[15].in=extension_in; device[15].out=extension_out; break;
213+ case 'x': use_extension=1; device[15].in=extension_in; device[15].out=extension_out; break;
214 case 'y': allow_write=0; device[10].out=device[11].out=files_out; device[10].in=device[11].in=files_in; break;
215 case 'z': zoom=strtol(optarg,0,10); break;
216 default: return 1;
+2,
-0
1@@ -226,6 +226,8 @@ long read since if you write to only 0xAC then the address is undefined.
2
3 (TODO)
4
5+See also emulator.doc for nonstandard meanings of delete/append ports.
6+
7
8 === Date/time ===
9