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