commit 2cff48e

Devine Lu Linvega  ·  2026-06-13 17:24:10 +0000 UTC
parent 3cd350a
Flushing on write cannot be helped
1 files changed,  +91, -80
+91, -80
  1@@ -641,48 +641,20 @@ mouse_deo_vector(void)
  2 #include <string.h>
  3 
  4 typedef struct {
  5-	FILE *f;
  6-	DIR *dir;
  7+	union {
  8+		FILE *f;
  9+		DIR *dir;
 10+	} h;
 11 	char *filepath;
 12 	enum { IDLE,
 13 		FILE_READ,
 14 		FILE_WRITE,
 15 		DIR_READ,
 16-		DIR_WRITE
 17-	} state;
 18+		DIR_WRITE } state;
 19 } UxnFile;
 20 
 21 static UxnFile ufs[2];
 22 
 23-static void
 24-make_pathfile(char *pathbuf, const char *filepath, const char *basename)
 25-{
 26-	char c = '/';
 27-	while(*filepath)
 28-		c = *filepath++, *pathbuf = c, pathbuf++;
 29-	if(c != '/')
 30-		*pathbuf = '/', pathbuf++;
 31-	while(*basename)
 32-		*pathbuf = *basename++, pathbuf++;
 33-	*pathbuf = 0;
 34-}
 35-
 36-static inline unsigned int
 37-put_fill(Uint8 *dest, unsigned int len, char c)
 38-{
 39-	memset(dest, c, len);
 40-	return len;
 41-}
 42-
 43-static inline unsigned int
 44-put_size(Uint8 *dest, unsigned int len, unsigned int size)
 45-{
 46-	unsigned int i;
 47-	for(i = 0, dest += len; i < len; i++, size >>= 4)
 48-		*(--dest) = "0123456789abcdef"[(Uint8)(size & 0xf)];
 49-	return len;
 50-}
 51-
 52 static inline unsigned int
 53 put_text(Uint8 *dest, const char *text)
 54 {
 55@@ -696,20 +668,29 @@ put_text(Uint8 *dest, const char *text)
 56 static unsigned int
 57 put_stat(Uint8 *dest, unsigned int len, unsigned int size, unsigned int err, unsigned int dir, unsigned int capsize)
 58 {
 59-	if(err) return put_fill(dest, len, '!');
 60-	if(dir) return put_fill(dest, len, '-');
 61-	if(capsize && size >= 0x10000) return put_fill(dest, len, '?');
 62-	return put_size(dest, len, size);
 63+	unsigned int i;
 64+	if(err || dir || (capsize && size >= 0x10000)) {
 65+		memset(dest, err ? '!' : dir ? '-' :
 66+									   '?',
 67+			len);
 68+		return len;
 69+	}
 70+	for(i = 0, dest += len; i < len; i++, size >>= 4)
 71+		*(--dest) = "0123456789abcdef"[(Uint8)(size & 0xf)];
 72+	return len;
 73 }
 74 
 75 static unsigned int
 76-put_statfile(Uint8 *dest, const char *filepath, const char *basename)
 77+put_statfile(Uint8 *dest, char *pathbuf, unsigned int prefix_len, unsigned int cap, const char *basename)
 78 {
 79 	unsigned int err, dir;
 80 	struct stat st;
 81 	Uint8 *anchor = dest;
 82-	char pathbuf[0x200];
 83-	make_pathfile(pathbuf, filepath, basename);
 84+	char *p = pathbuf + prefix_len, *end = pathbuf + cap - 1;
 85+	const char *b = basename;
 86+	while(*b && p < end)
 87+		*p++ = *b++;
 88+	*p = 0;
 89 	err = stat(pathbuf, &st);
 90 	dir = !err && S_ISDIR(st.st_mode);
 91 	dest += put_stat(dest, 4, st.st_size, err, dir, 1);
 92@@ -724,11 +705,19 @@ put_fdir(Uint8 *dest, unsigned int len, const char *filepath, DIR *dir)
 93 {
 94 	Uint8 *p = dest, *end = dest + len - 1;
 95 	struct dirent *de;
 96+	char pathbuf[0x200];
 97+	unsigned int prefix_len = 0;
 98+	char c = '/';
 99+	const char *fp = filepath;
100+	while(*fp && prefix_len < sizeof pathbuf - 1)
101+		c = *fp++, pathbuf[prefix_len++] = c;
102+	if(c != '/' && prefix_len < sizeof pathbuf - 1)
103+		pathbuf[prefix_len++] = '/';
104 	while((de = readdir(dir)) && p < end) {
105 		const char *name = de->d_name;
106 		if(name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
107 			continue;
108-		p += put_statfile(p, filepath, name);
109+		p += put_statfile(p, pathbuf, prefix_len, sizeof pathbuf, name);
110 	}
111 	*p = 0;
112 	return p - dest;
113@@ -753,9 +742,9 @@ static unsigned int
114 file_write_dir(const char *p)
115 {
116 	char buf[0x200];
117-	char *s = buf;
118+	char *s = buf, *end = buf + sizeof buf - 1;
119 	unsigned int ok = 1;
120-	while(*p && ok) {
121+	while(*p && ok && s < end) {
122 		*s++ = *p;
123 		if(*p++ == '/') {
124 			s[-1] = '\0';
125@@ -763,17 +752,50 @@ file_write_dir(const char *p)
126 			s[-1] = '/';
127 		}
128 	}
129-	return ok;
130+	return ok && !*p;
131 }
132 
133 static void
134 file_reset(unsigned int id)
135 {
136-	if(ufs[id].f != NULL) fclose(ufs[id].f), ufs[id].f = NULL;
137-	if(ufs[id].dir != NULL) closedir(ufs[id].dir), ufs[id].dir = NULL;
138+	switch(ufs[id].state) {
139+	case FILE_READ:
140+	case FILE_WRITE: fclose(ufs[id].h.f); break;
141+	case DIR_READ: closedir(ufs[id].h.dir); break;
142+	default: break;
143+	}
144 	ufs[id].state = IDLE;
145 }
146 
147+static unsigned int
148+file_open(unsigned int id, unsigned int want_write, Uint8 flags)
149+{
150+	UxnFile *u = &ufs[id];
151+	struct stat st;
152+	if(want_write) {
153+		if(u->state == FILE_WRITE || u->state == DIR_WRITE)
154+			return 1;
155+		file_reset(id);
156+		file_write_dir(u->filepath);
157+		if(is_dir_path(u->filepath)) {
158+			u->state = is_dir_real(u->filepath) ? DIR_WRITE : IDLE;
159+		} else if((u->h.f = fopen(u->filepath, (flags & 0x01) ? "ab" : "wb"))) {
160+			u->state = FILE_WRITE;
161+		}
162+	} else {
163+		if(u->state == FILE_READ || u->state == DIR_READ)
164+			return 1;
165+		file_reset(id);
166+		if(stat(u->filepath, &st) == 0 && S_ISDIR(st.st_mode)) {
167+			if((u->h.dir = opendir(u->filepath)))
168+				u->state = DIR_READ;
169+		} else if((u->h.f = fopen(u->filepath, "rb"))) {
170+			u->state = FILE_READ;
171+		}
172+	}
173+	return u->state != IDLE;
174+}
175+
176 static unsigned int
177 file_init(unsigned int id, Uint16 addr)
178 {
179@@ -786,55 +808,35 @@ static unsigned int
180 file_read(unsigned int id, Uint16 addr, unsigned int len)
181 {
182 	void *dest = &ram[addr];
183-	struct stat st;
184 	unsigned int n;
185 	if(ufs[id].filepath == 0)
186 		return 0;
187 	if(addr + len > 0x10000)
188 		len = 0x10000 - addr;
189-	if(ufs[id].state != FILE_READ && ufs[id].state != DIR_READ) {
190-		file_reset(id);
191-		if(stat(ufs[id].filepath, &st) == 0 && S_ISDIR(st.st_mode)) {
192-			if((ufs[id].dir = opendir(ufs[id].filepath)) != NULL)
193-				ufs[id].state = DIR_READ;
194-		} else if((ufs[id].f = fopen(ufs[id].filepath, "rb")) != NULL) {
195-			ufs[id].state = FILE_READ;
196-		}
197-	}
198-	if(ufs[id].state == FILE_READ) {
199-		n = fread(dest, 1, len, ufs[id].f);
200-		if(n == 0) file_reset(id);
201-		return n;
202-	}
203-	if(ufs[id].state == DIR_READ) {
204-		n = put_fdir(dest, len, ufs[id].filepath, ufs[id].dir);
205-		if(n == 0) file_reset(id);
206-		return n;
207-	}
208-	return 0;
209+	if(!file_open(id, 0, 0))
210+		return 0;
211+	if(ufs[id].state == FILE_READ)
212+		n = fread(dest, 1, len, ufs[id].h.f);
213+	else
214+		n = put_fdir(dest, len, ufs[id].filepath, ufs[id].h.dir);
215+	if(n == 0) file_reset(id);
216+	return n;
217 }
218 
219 static unsigned int
220 file_write(unsigned int id, Uint16 addr, unsigned int len, Uint8 flags)
221 {
222-	unsigned int ret = 0;
223 	if(ufs[id].filepath == 0)
224 		return 0;
225 	if(addr + len > 0x10000)
226 		len = 0x10000 - addr;
227-	if(ufs[id].state != FILE_WRITE && ufs[id].state != DIR_WRITE) {
228-		file_reset(id);
229-		file_write_dir(ufs[id].filepath);
230-		if(is_dir_path(ufs[id].filepath))
231-			ufs[id].state = DIR_WRITE;
232-		else if((ufs[id].f = fopen(ufs[id].filepath, (flags & 0x01) ? "ab" : "wb")) != NULL)
233-			ufs[id].state = FILE_WRITE;
234+	if(!file_open(id, 1, flags))
235+		return 0;
236+	if(ufs[id].state == FILE_WRITE) {
237+		unsigned int ret = fwrite(&ram[addr], 1, len, ufs[id].h.f);
238+		return (ret > 0 && fflush(ufs[id].h.f) != 0) ? 0 : ret;
239 	}
240-	if(ufs[id].state == FILE_WRITE)
241-		ret = fwrite(&ram[addr], 1, len, ufs[id].f);
242-	if(ufs[id].state == DIR_WRITE)
243-		ret = is_dir_real(ufs[id].filepath);
244-	return ret;
245+	return is_dir_real(ufs[id].filepath);
246 }
247 
248 static unsigned int
249@@ -1115,6 +1117,15 @@ emu_restart(unsigned int soft)
250 	uxn_eval(0x100);
251 }
252 
253+static inline unsigned int
254+put_size(Uint8 *dest, unsigned int len, unsigned int size)
255+{
256+	unsigned int i;
257+	for(i = 0, dest += len; i < len; i++, size >>= 4)
258+		*(--dest) = "0123456789abcdef"[(Uint8)(size & 0xf)];
259+	return len;
260+}
261+
262 static void
263 emu_screenshot(void)
264 {