1 /*
2 * $Id: files.c,v 1.2 2009-05-22 04:02:26 dhmunro Exp $
3 * MS Windows version of plib file operations
4 */
5 /* Copyright (c) 2005, The Regents of the University of California.
6 * All rights reserved.
7 * This file is part of yorick (http://yorick.sourceforge.net).
8 * Read the accompanying LICENSE file for details.
9 */
10
11 #include "config.h"
12 #include "pstdio.h"
13 #include "pstdlib.h"
14 #include "playw.h"
15
16 #include <stdio.h>
17 #include <io.h>
18 #include <fcntl.h>
19
20 struct p_file {
21 p_file_ops *ops;
22 FILE *fp; /* use FILE* for text file operations */
23 int fd; /* use file descriptor for binary file operations */
24 int binary;
25 };
26
27 static unsigned long pv_fsize(p_file *file);
28 static unsigned long pv_ftell(p_file *file);
29 static int pv_fseek(p_file *file, unsigned long addr);
30
31 static char *pv_fgets(p_file *file, char *buf, int buflen);
32 static int pv_fputs(p_file *file, const char *buf);
33 static unsigned long pv_fread(p_file *file,
34 void *buf, unsigned long nbytes);
35 static unsigned long pv_fwrite(p_file *file,
36 const void *buf, unsigned long nbytes);
37
38 static int pv_feof(p_file *file);
39 static int pv_ferror(p_file *file);
40 static int pv_fflush(p_file *file);
41 static int pv_fclose(p_file *file);
42
43 static p_file_ops w_file_ops = {
44 &pv_fsize, &pv_ftell, &pv_fseek,
45 &pv_fgets, &pv_fputs, &pv_fread, &pv_fwrite,
46 &pv_feof, &pv_ferror, &pv_fflush, &pv_fclose };
47
48 p_file *
p_fopen(const char * unix_name,const char * mode)49 p_fopen(const char *unix_name, const char *mode)
50 {
51 FILE *fp = fopen(w_pathname(unix_name), mode);
52 p_file *f = fp? p_malloc(sizeof(p_file)) : 0;
53 if (f) {
54 f->ops = &w_file_ops;
55 f->fp = fp;
56 f->fd = _fileno(fp);
57 for (; mode[0] ; mode++) if (mode[0]=='b') break;
58 f->binary = (mode[0]=='b');
59 /* problem:
60 * in _O_TEXT mode, ftell only works properly if the file
61 * really is a DOS file with CRLF newlines; if it is a UNIX
62 * file (like all of the distribution .i files), ftell fails
63 * on the other hand, using _O_BINARY makes fgets fail to remove
64 * the CR and fputs not insert CR
65 * (may depend on Windows flavor, this is Win2k */
66 if (!f->binary) _setmode(f->fd, _O_BINARY);
67 }
68 return f;
69 }
70
71 p_file *
p_popen(const char * command,const char * mode)72 p_popen(const char *command, const char *mode)
73 {
74 /* WARNING- for non-console programs, returned FILE* causes
75 * program to hang forever (according to msdn documentation) */
76 FILE *fp = _popen(command, mode);
77 p_file *f = fp? p_malloc(sizeof(p_file)) : 0;
78 if (f) {
79 f->ops = &w_file_ops;
80 f->fp = fp;
81 f->fd = _fileno(fp);
82 for (; mode[0] ; mode++) if (mode[0]=='b') break;
83 f->binary = (mode[0]=='b') | 2;
84 }
85 return f;
86 }
87
88 p_file *
p_fd_raw(int fd)89 p_fd_raw(int fd)
90 {
91 p_file *f = p_malloc(sizeof(p_file));
92 if (f) {
93 f->ops = &w_file_ops;
94 f->fp = 0;
95 f->fd = fd;
96 f->binary = 5;
97 }
98 return f;
99 }
100
101 static int
pv_fclose(p_file * file)102 pv_fclose(p_file *file)
103 {
104 int flag;
105 if (!file->fp) flag = _close(file->fd);
106 else flag = (file->binary&2)? _pclose(file->fp) : fclose(file->fp);
107 p_free(file);
108 return flag;
109 }
110
111 static char *
pv_fgets(p_file * file,char * buf,int buflen)112 pv_fgets(p_file *file, char *buf, int buflen)
113 {
114 char *b = fgets(buf, buflen, file->fp);
115 if (b) {
116 /* remove CR if line ends with CRLF */
117 int n;
118 for (n=0 ; n<buflen-2 ; n++) {
119 if (!buf[n]) break;
120 if (buf[n]=='\015' && buf[n+1]=='\n' && buf[n+2]=='\0')
121 buf[n] = '\n', buf[n+1] = '\0';
122 }
123 }
124 return b;
125 }
126
127 static int
pv_fputs(p_file * file,const char * buf)128 pv_fputs(p_file *file, const char *buf)
129 {
130 int n, dn, i;
131 char b[1026];
132 for (n=0 ;;) {
133 for (i=0 ; i<1024 ; i++,buf++) {
134 if (!buf[0]) break;
135 if (buf[0] == '\n') b[i++] = '\015';
136 b[i] = buf[0];
137 }
138 b[i] = '\0';
139 dn = fputs(b, file->fp);
140 if (dn < 0) return dn;
141 n += dn;
142 if (!buf[0]) break;
143 }
144 return n;
145 }
146
147 static unsigned long
pv_fread(p_file * file,void * buf,unsigned long nbytes)148 pv_fread(p_file *file, void *buf, unsigned long nbytes)
149 {
150 if (file->binary&1) {
151 return _read(file->fd, buf, nbytes);
152 } else {
153 return fread(buf, 1, nbytes, file->fp);
154 }
155 }
156
157 static unsigned long
pv_fwrite(p_file * file,const void * buf,unsigned long nbytes)158 pv_fwrite(p_file *file, const void *buf, unsigned long nbytes)
159 {
160 if (file->binary&1) {
161 return _write(file->fd, buf, nbytes);
162 } else {
163 return fwrite(buf, 1, nbytes, file->fp);
164 }
165 }
166
167 static unsigned long
pv_ftell(p_file * file)168 pv_ftell(p_file *file)
169 {
170 if (file->binary&1)
171 return _tell(file->fd);
172 else /* broken in _O_TEXT mode, see p_fopen */
173 return ftell(file->fp);
174 }
175
176 static int
pv_fseek(p_file * file,unsigned long addr)177 pv_fseek(p_file *file, unsigned long addr)
178 {
179 if (file->binary&1)
180 return -(_lseek(file->fd, addr, SEEK_SET)==-1L);
181 else
182 return fseek(file->fp, addr, SEEK_SET);
183 }
184
185 static int
pv_fflush(p_file * file)186 pv_fflush(p_file *file)
187 {
188 return fflush(file->fp);
189 }
190
191 static int
pv_feof(p_file * file)192 pv_feof(p_file *file)
193 {
194 return feof(file->fp);
195 }
196
197 static int
pv_ferror(p_file * file)198 pv_ferror(p_file *file)
199 {
200 int flag = ferror(file->fp);
201 clearerr(file->fp);
202 return flag;
203 }
204
205 static unsigned long
pv_fsize(p_file * file)206 pv_fsize(p_file *file)
207 {
208 return _filelength(file->fd);
209 }
210
211 int
p_remove(const char * unix_name)212 p_remove(const char *unix_name)
213 {
214 return -(!DeleteFile(w_pathname(unix_name)));
215 }
216
217 int
p_rename(const char * unix_old,const char * unix_new)218 p_rename(const char *unix_old, const char *unix_new)
219 {
220 char old[P_WKSIZ+1];
221 old[0] = '\0';
222 strncat(old, w_pathname(unix_old), P_WKSIZ);
223 return -(!MoveFile(old, w_pathname(unix_new)));
224 }
225
226 char *
p_native(const char * unix_name)227 p_native(const char *unix_name)
228 {
229 return p_strcpy(w_pathname(unix_name));
230 }
231