Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* sim_fio.c: simulator file I/O library\r |
2 | \r | |
3 | Copyright (c) 1993-2006, Robert M Supnik\r | |
4 | \r | |
5 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
6 | copy of this software and associated documentation files (the "Software"),\r | |
7 | to deal in the Software without restriction, including without limitation\r | |
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
9 | and/or sell copies of the Software, and to permit persons to whom the\r | |
10 | Software is furnished to do so, subject to the following conditions:\r | |
11 | \r | |
12 | The above copyright notice and this permission notice shall be included in\r | |
13 | all copies or substantial portions of the Software.\r | |
14 | \r | |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
21 | \r | |
22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r | |
23 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
24 | in this Software without prior written authorization from Robert M Supnik.\r | |
25 | \r | |
26 | 28-Jun-07 RMS Added VMS IA64 support (from Norm Lastovica)\r | |
27 | 10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman)\r | |
28 | 15-May-06 RMS Added sim_fsize_name\r | |
29 | 21-Apr-06 RMS Added FreeBSD large file support (from Mark Martinec)\r | |
30 | 19-Nov-05 RMS Added OS/X large file support (from Peter Schorn)\r | |
31 | 16-Aug-05 RMS Fixed C++ declaration and cast problems\r | |
32 | 17-Jul-04 RMS Fixed bug in optimized sim_fread (reported by Scott Bailey)\r | |
33 | 26-May-04 RMS Optimized sim_fread (suggested by John Dundas)\r | |
34 | 02-Jan-04 RMS Split out from SCP\r | |
35 | \r | |
36 | This library includes:\r | |
37 | \r | |
38 | sim_finit - initialize package\r | |
39 | sim_fopen - open file\r | |
40 | sim_fread - endian independent read (formerly fxread)\r | |
41 | sim_write - endian independent write (formerly fxwrite)\r | |
42 | sim_fseek - extended (>32b) seek (formerly fseek_ext)\r | |
43 | sim_fsize - get file size\r | |
44 | \r | |
45 | sim_fopen and sim_fseek are OS-dependent. The other routines are not.\r | |
46 | sim_fsize is always a 32b routine (it is used only with small capacity random\r | |
47 | access devices like fixed head disks and DECtapes).\r | |
48 | */\r | |
49 | \r | |
50 | #include "sim_defs.h"\r | |
51 | \r | |
52 | static unsigned char sim_flip[FLIP_SIZE];\r | |
53 | int32 sim_end = 1; /* 1 = little */\r | |
54 | \r | |
55 | /* OS-independent, endian independent binary I/O package\r | |
56 | \r | |
57 | For consistency, all binary data read and written by the simulator\r | |
58 | is stored in little endian data order. That is, in a multi-byte\r | |
59 | data item, the bytes are written out right to left, low order byte\r | |
60 | to high order byte. On a big endian host, data is read and written\r | |
61 | from high byte to low byte. Consequently, data written on a little\r | |
62 | endian system must be byte reversed to be usable on a big endian\r | |
63 | system, and vice versa.\r | |
64 | \r | |
65 | These routines are analogs of the standard C runtime routines\r | |
66 | fread and fwrite. If the host is little endian, or the data items\r | |
67 | are size char, then the calls are passed directly to fread or\r | |
68 | fwrite. Otherwise, these routines perform the necessary byte swaps.\r | |
69 | Sim_fread swaps in place, sim_fwrite uses an intermediate buffer.\r | |
70 | */\r | |
71 | \r | |
72 | int32 sim_finit (void)\r | |
73 | {\r | |
74 | union {int32 i; char c[sizeof (int32)]; } end_test;\r | |
75 | \r | |
76 | end_test.i = 1; /* test endian-ness */\r | |
77 | sim_end = end_test.c[0];\r | |
78 | return sim_end;\r | |
79 | }\r | |
80 | \r | |
81 | size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr)\r | |
82 | {\r | |
83 | size_t c, j;\r | |
84 | int32 k;\r | |
85 | unsigned char by, *sptr, *dptr;\r | |
86 | \r | |
87 | if ((size == 0) || (count == 0)) return 0; /* check arguments */\r | |
88 | c = fread (bptr, size, count, fptr); /* read buffer */\r | |
89 | if (sim_end || (size == sizeof (char)) || (c == 0)) /* le, byte, or err? */\r | |
90 | return c; /* done */\r | |
91 | for (j = 0, dptr = sptr = (unsigned char *) bptr; j < c; j++) { /* loop on items */\r | |
92 | for (k = size - 1; k >= (((int32) size + 1) / 2); k--) {\r | |
93 | by = *sptr; /* swap end-for-end */\r | |
94 | *sptr++ = *(dptr + k);\r | |
95 | *(dptr + k) = by;\r | |
96 | }\r | |
97 | sptr = dptr = dptr + size; /* next item */\r | |
98 | }\r | |
99 | return c;\r | |
100 | }\r | |
101 | \r | |
102 | size_t sim_fwrite (void *bptr, size_t size, size_t count, FILE *fptr)\r | |
103 | {\r | |
104 | size_t c, j, nelem, nbuf, lcnt, total;\r | |
105 | int32 i, k;\r | |
106 | unsigned char *sptr, *dptr;\r | |
107 | \r | |
108 | if ((size == 0) || (count == 0)) return 0; /* check arguments */\r | |
109 | if (sim_end || (size == sizeof (char))) /* le or byte? */\r | |
110 | return fwrite (bptr, size, count, fptr); /* done */\r | |
111 | nelem = FLIP_SIZE / size; /* elements in buffer */\r | |
112 | nbuf = count / nelem; /* number buffers */\r | |
113 | lcnt = count % nelem; /* count in last buf */\r | |
114 | if (lcnt) nbuf = nbuf + 1;\r | |
115 | else lcnt = nelem;\r | |
116 | total = 0;\r | |
117 | sptr = (unsigned char *) bptr; /* init input ptr */\r | |
118 | for (i = nbuf; i > 0; i--) { /* loop on buffers */\r | |
119 | c = (i == 1)? lcnt: nelem;\r | |
120 | for (j = 0, dptr = sim_flip; j < c; j++) { /* loop on items */\r | |
121 | for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++;\r | |
122 | dptr = dptr + size;\r | |
123 | }\r | |
124 | c = fwrite (sim_flip, size, c, fptr);\r | |
125 | if (c == 0) return total;\r | |
126 | total = total + c;\r | |
127 | }\r | |
128 | return total;\r | |
129 | }\r | |
130 | \r | |
131 | /* Get file size */\r | |
132 | \r | |
133 | uint32 sim_fsize_name (char *fname)\r | |
134 | {\r | |
135 | FILE *fp;\r | |
136 | uint32 sz;\r | |
137 | \r | |
138 | if ((fp = sim_fopen (fname, "rb")) == NULL) return 0;\r | |
139 | sz = sim_fsize (fp);\r | |
140 | fclose (fp);\r | |
141 | return sz;\r | |
142 | }\r | |
143 | \r | |
144 | uint32 sim_fsize (FILE *fp)\r | |
145 | {\r | |
146 | uint32 pos, sz;\r | |
147 | \r | |
148 | if (fp == NULL) return 0;\r | |
149 | pos = ftell (fp);\r | |
150 | fseek (fp, 0, SEEK_END);\r | |
151 | sz = ftell (fp);\r | |
152 | fseek (fp, pos, SEEK_SET);\r | |
153 | return sz;\r | |
154 | }\r | |
155 | \r | |
156 | /* OS-dependent routines */\r | |
157 | \r | |
158 | /* Optimized file open */\r | |
159 | \r | |
160 | FILE *sim_fopen (const char *file, const char *mode)\r | |
161 | {\r | |
162 | #if defined (VMS)\r | |
163 | return fopen (file, mode, "ALQ=32", "DEQ=4096",\r | |
164 | "MBF=6", "MBC=127", "FOP=cbt,tef", "ROP=rah,wbh", "CTX=stm");\r | |
165 | #elif defined (USE_INT64) && defined (USE_ADDR64) && defined (__linux)\r | |
166 | return fopen64 (file, mode);\r | |
167 | #else\r | |
168 | return fopen (file, mode);\r | |
169 | #endif\r | |
170 | }\r | |
171 | \r | |
172 | /* Long seek */\r | |
173 | \r | |
174 | #if defined (USE_INT64) && defined (USE_ADDR64)\r | |
175 | \r | |
176 | /* 64b VMS */\r | |
177 | \r | |
178 | #if (defined (__ALPHA) || defined (__ia64)) && defined (VMS) /* 64b VMS */\r | |
179 | #define _SIM_IO_FSEEK_EXT_ 1\r | |
180 | \r | |
181 | static t_int64 fpos_t_to_int64 (fpos_t *pos)\r | |
182 | {\r | |
183 | unsigned short *w = (unsigned short *) pos; /* endian dep! */\r | |
184 | t_int64 result;\r | |
185 | \r | |
186 | result = w[1];\r | |
187 | result <<= 16;\r | |
188 | result += w[0];\r | |
189 | result <<= 9;\r | |
190 | result += w[2];\r | |
191 | return result;\r | |
192 | }\r | |
193 | \r | |
194 | static void int64_to_fpos_t (t_int64 ipos, fpos_t *pos, size_t mbc)\r | |
195 | {\r | |
196 | unsigned short *w = (unsigned short *) pos;\r | |
197 | int bufsize = mbc << 9;\r | |
198 | \r | |
199 | w[3] = 0;\r | |
200 | w[2] = (unsigned short) (ipos % bufsize);\r | |
201 | ipos -= w[2];\r | |
202 | ipos >>= 9;\r | |
203 | w[0] = (unsigned short) ipos;\r | |
204 | ipos >>= 16;\r | |
205 | w[1] = (unsigned short) ipos;\r | |
206 | if ((w[2] == 0) && (w[0] || w[1])) {\r | |
207 | w[2] = bufsize;\r | |
208 | w[0] -= mbc;\r | |
209 | }\r | |
210 | return;\r | |
211 | }\r | |
212 | \r | |
213 | int sim_fseek (FILE *st, t_addr offset, int whence)\r | |
214 | {\r | |
215 | t_addr fileaddr;\r | |
216 | fpos_t filepos;\r | |
217 | \r | |
218 | switch (whence) {\r | |
219 | \r | |
220 | case SEEK_SET:\r | |
221 | fileaddr = offset;\r | |
222 | break;\r | |
223 | \r | |
224 | case SEEK_CUR:\r | |
225 | if (fgetpos (st, &filepos)) return (-1);\r | |
226 | fileaddr = fpos_t_to_int64 (&filepos);\r | |
227 | fileaddr = fileaddr + offset;\r | |
228 | break;\r | |
229 | \r | |
230 | default:\r | |
231 | errno = EINVAL;\r | |
232 | return (-1);\r | |
233 | }\r | |
234 | \r | |
235 | int64_to_fpos_t (fileaddr, &filepos, 127);\r | |
236 | return fsetpos (st, &filepos);\r | |
237 | }\r | |
238 | \r | |
239 | #endif\r | |
240 | \r | |
241 | /* Alpha UNIX - natively 64b */\r | |
242 | \r | |
243 | #if defined (__ALPHA) && defined (__unix__) /* Alpha UNIX */\r | |
244 | #define _SIM_IO_FSEEK_EXT_ 1\r | |
245 | \r | |
246 | int sim_fseek (FILE *st, t_addr offset, int whence)\r | |
247 | {\r | |
248 | return fseek (st, offset, whence);\r | |
249 | }\r | |
250 | \r | |
251 | #endif\r | |
252 | \r | |
253 | /* Windows */\r | |
254 | \r | |
255 | #if defined (_WIN32)\r | |
256 | #define _SIM_IO_FSEEK_EXT_ 1\r | |
257 | \r | |
258 | int sim_fseek (FILE *st, t_addr offset, int whence)\r | |
259 | {\r | |
260 | fpos_t fileaddr;\r | |
261 | \r | |
262 | switch (whence) {\r | |
263 | \r | |
264 | case SEEK_SET:\r | |
265 | fileaddr = offset;\r | |
266 | break;\r | |
267 | \r | |
268 | case SEEK_CUR:\r | |
269 | if (fgetpos (st, &fileaddr)) return (-1);\r | |
270 | fileaddr = fileaddr + offset;\r | |
271 | break;\r | |
272 | \r | |
273 | default:\r | |
274 | errno = EINVAL;\r | |
275 | return (-1);\r | |
276 | }\r | |
277 | \r | |
278 | return fsetpos (st, &fileaddr);\r | |
279 | }\r | |
280 | \r | |
281 | #endif /* end Windows */\r | |
282 | \r | |
283 | /* Linux */\r | |
284 | \r | |
285 | #if defined (__linux)\r | |
286 | #define _SIM_IO_FSEEK_EXT_ 1\r | |
287 | \r | |
288 | int sim_fseek (FILE *st, t_addr xpos, int origin)\r | |
289 | {\r | |
290 | return fseeko64 (st, xpos, origin);\r | |
291 | }\r | |
292 | \r | |
293 | #endif /* end Linux with LFS */\r | |
294 | \r | |
295 | /* Apple OS/X */\r | |
296 | \r | |
297 | #if defined (__APPLE__) || defined (__FreeBSD__)\r | |
298 | #define _SIM_IO_FSEEK_EXT_ 1\r | |
299 | \r | |
300 | int sim_fseek (FILE *st, t_addr xpos, int origin) \r | |
301 | {\r | |
302 | return fseeko (st, xpos, origin);\r | |
303 | }\r | |
304 | \r | |
305 | #endif /* end Apple OS/X */\r | |
306 | \r | |
307 | #endif /* end 64b seek defs */\r | |
308 | \r | |
309 | /* Default: no OS-specific routine has been defined */\r | |
310 | \r | |
311 | #if !defined (_SIM_IO_FSEEK_EXT_)\r | |
312 | #define _SIM_IO_FSEEK_EXT_ 0\r | |
313 | \r | |
314 | int sim_fseek (FILE *st, t_addr xpos, int origin)\r | |
315 | {\r | |
316 | return fseek (st, (int32) xpos, origin);\r | |
317 | }\r | |
318 | \r | |
319 | #endif\r | |
320 | \r | |
321 | uint32 sim_taddr_64 = _SIM_IO_FSEEK_EXT_;\r |