1 /* SCCS Id: @(#)macfile.c 3.1 93/01/24 */
2 /* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */
3 /* NetHack may be freely redistributed. See license for details. */
4 /*
5 * macfile.c
6 * MAC file I/O routines
7 */
8
9 #include "hack.h"
10 #include "macwin.h"
11
12 #ifndef __MACH__
13 #include <files.h>
14 #include <errors.h>
15 #include <resources.h>
16 #include <memory.h>
17 #include <TextUtils.h>
18 #include <ToolUtils.h>
19 #endif
20
21 #include "dlb.h"
22
23 /*
24 * We should get the default dirID and volRefNum (from name) from prefs and
25 * the situation at startup... For now, this will have to do.
26 */
27
28
29 /* The HandleFiles are resources built into the application which are treated
30 as read-only files: if we fail to open a file we look for a resource */
31
32 #define FIRST_HF 32000 /* file ID of first HandleFile */
33 #define MAX_HF 6 /* Max # of open HandleFiles */
34
35 #define APP_NAME_RES_ID (-16396)
36
37 typedef struct handlefile {
38 long type; /* Resource type */
39 short id; /* Resource id */
40 long mark; /* Current position */
41 long size; /* total size */
42 Handle data; /* The resource, purgeable */
43 } HandleFile;
44
45 static HandleFile *FDECL(IsHandleFile,(int));
46 static int FDECL(OpenHandleFile,(const unsigned char *, long));
47 static int FDECL(CloseHandleFile,(int));
48 static int FDECL(ReadHandleFile,(int, void *, unsigned));
49 static long FDECL(SetHandleFilePos,(int, short, long));
50
51 HandleFile theHandleFiles [MAX_HF];
52 MacDirs theDirs; /* also referenced in macwin.c */
53
54
55 static HandleFile *
IsHandleFile(int fd)56 IsHandleFile(int fd)
57 {
58 HandleFile *hfp = NULL;
59
60 if (fd >= FIRST_HF && fd < FIRST_HF+MAX_HF) {
61 /* in valid range, check for data */
62 hfp = &theHandleFiles[fd-FIRST_HF];
63 if (!hfp->data) hfp = NULL;
64 }
65 return hfp;
66 }
67
68
69 static int
OpenHandleFile(const unsigned char * name,long fileType)70 OpenHandleFile (const unsigned char *name, long fileType)
71 {
72 int i;
73 Handle h;
74 Str255 s;
75
76 for (i = 0; i < MAX_HF; i ++) {
77 if (theHandleFiles[i].data == 0L) break;
78 }
79
80 if (i >= MAX_HF)
81 return -1;
82
83 h = GetNamedResource (fileType, name);
84 if (!h) return (-1);
85
86 theHandleFiles[i].data = h;
87 theHandleFiles[i].size = GetHandleSize (h);
88 GetResInfo (h, &theHandleFiles[i].id, (void*) &theHandleFiles[i].type, s);
89 theHandleFiles[i].mark = 0L;
90
91 return(i + FIRST_HF);
92 }
93
94
95 static int
CloseHandleFile(int fd)96 CloseHandleFile (int fd)
97 {
98 if (!IsHandleFile (fd)) {
99 return -1;
100 }
101 fd -= FIRST_HF;
102 ReleaseResource (theHandleFiles[fd].data);
103 theHandleFiles[fd].data = 0L;
104 return(0);
105 }
106
107
108 static int
ReadHandleFile(int fd,void * ptr,unsigned len)109 ReadHandleFile (int fd, void *ptr, unsigned len)
110 {
111 unsigned maxBytes;
112 Handle h;
113
114 if (!IsHandleFile (fd)) return -1;
115
116 fd -= FIRST_HF;
117 maxBytes = theHandleFiles[fd].size - theHandleFiles[fd].mark;
118 if (len > maxBytes) len = maxBytes;
119
120 h = theHandleFiles[fd].data;
121
122 HLock(h);
123 BlockMove (*h + theHandleFiles[fd].mark, ptr, len);
124 HUnlock(h);
125 theHandleFiles[fd].mark += len;
126
127 return(len);
128 }
129
130
131 static long
SetHandleFilePos(int fd,short whence,long pos)132 SetHandleFilePos (int fd, short whence, long pos)
133 {
134 long curpos;
135
136 if (!IsHandleFile (fd)) return -1;
137
138 fd -= FIRST_HF;
139
140 curpos = theHandleFiles [fd].mark;
141 switch (whence) {
142 case SEEK_CUR :
143 curpos += pos;
144 break;
145 case SEEK_END :
146 curpos = theHandleFiles[fd].size - pos;
147 break;
148 default : /* set */
149 curpos = pos;
150 break;
151 }
152
153 if (curpos < 0)
154 curpos = 0;
155 else if (curpos > theHandleFiles [fd].size)
156 curpos = theHandleFiles [fd].size;
157
158 theHandleFiles [fd].mark = curpos;
159
160 return curpos;
161 }
162
163
164 void
C2P(const char * c,unsigned char * p)165 C2P (const char *c, unsigned char *p)
166 {
167 int len = strlen (c), i;
168
169 if (len > 255) len = 255;
170
171 for (i = len; i > 0; i--)
172 p[i] = c[i-1];
173 p[0] = len;
174 }
175
176 void
P2C(const unsigned char * p,char * c)177 P2C (const unsigned char *p, char *c)
178 {
179 int idx = *p++;
180 for (; idx > 0; idx--)
181 *c++ = *p++;
182 *c = '\0';
183 }
184
185
186 static void
replace_resource(Handle new_res,ResType its_type,short its_id,Str255 its_name)187 replace_resource(Handle new_res, ResType its_type, short its_id, Str255 its_name)
188 {
189 Handle old_res;
190
191 SetResLoad(false);
192 old_res = Get1Resource(its_type, its_id);
193 SetResLoad(true);
194 if (old_res) {
195 RemoveResource(old_res);
196 DisposeHandle(old_res);
197 }
198
199 AddResource(new_res, its_type, its_id, its_name);
200 }
201
202
203 int
maccreat(const char * name,long fileType)204 maccreat (const char *name, long fileType){
205 return macopen (name, O_RDWR | O_CREAT | O_TRUNC, fileType);
206 }
207
208
209 int
macopen(const char * name,int flags,long fileType)210 macopen (const char *name, int flags, long fileType)
211 {
212 short refNum;
213 short perm;
214 Str255 s;
215
216 C2P (name, s);
217 if (flags & O_CREAT) {
218 if (HCreate (theDirs.dataRefNum, theDirs.dataDirID, s ,
219 TEXT_CREATOR, fileType) && (flags & O_EXCL)) {
220 return -1;
221 }
222
223 if (fileType == SAVE_TYPE) {
224 short resRef;
225 HCreateResFile(theDirs.dataRefNum, theDirs.dataDirID, s);
226 resRef = HOpenResFile(theDirs.dataRefNum, theDirs.dataDirID, s,
227 fsRdWrPerm);
228 if (resRef != -1) {
229 Handle name;
230 Str255 plnamep;
231
232 C2P(plname, plnamep);
233 name = (Handle)NewString(plnamep);
234 if (name)
235 replace_resource(name, 'STR ', PLAYER_NAME_RES_ID,
236 "\pPlayer Name");
237
238 /* The application name resource. See IM VI, page 9-21. */
239 name = (Handle)GetString(APP_NAME_RES_ID);
240 if (name) {
241 DetachResource(name);
242 replace_resource(name, 'STR ', APP_NAME_RES_ID,
243 "\pApplication Name");
244 }
245
246 CloseResFile(resRef);
247 }
248 }
249
250 }
251 /*
252 * Here, we should check for file type, maybe a SFdialog if
253 * we fail with default, etc. etc. Besides, we should use HOpen
254 * and permissions.
255 */
256 if ((flags & O_RDONLY) == O_RDONLY) {
257 perm = fsRdPerm;
258 }
259 if ((flags & O_WRONLY) == O_WRONLY) {
260 perm = fsWrPerm;
261 }
262 if ((flags & O_RDWR) == O_RDWR) {
263 perm = fsRdWrPerm;
264 }
265 if (HOpen (theDirs.dataRefNum, theDirs.dataDirID, s, perm, &refNum)) {
266 return OpenHandleFile (s, fileType);
267 }
268 if (flags & O_TRUNC) {
269 if (SetEOF (refNum, 0L)) {
270 FSClose (refNum);
271 return -1;
272 }
273 }
274 return refNum;
275 }
276
277
278 int
macclose(int fd)279 macclose (int fd)
280 {
281 if (IsHandleFile (fd)) {
282 CloseHandleFile (fd);
283 } else {
284 if (FSClose (fd)) {
285 return -1;
286 }
287 FlushVol ((StringPtr) 0, theDirs . dataRefNum);
288 }
289 return 0;
290 }
291
292
293 int
macread(int fd,void * ptr,unsigned len)294 macread (int fd, void *ptr, unsigned len)
295 {
296 long amt = len;
297
298 if (IsHandleFile (fd)) {
299 return ReadHandleFile (fd, ptr, amt);
300 } else {
301 short err = FSRead (fd, &amt, ptr);
302
303 return ((err == noErr) || (err == eofErr && len)) ? amt : -1;
304 }
305 }
306
307
308 #if 0 /* this function isn't used, if you use it, uncomment prototype in macwin.h */
309 char *
310 macgets (int fd, char *ptr, unsigned len)
311 {
312 int idx = 0;
313 char c;
314
315 while (-- len > 0) {
316 if (macread (fd, ptr + idx, 1) <= 0)
317 return (char *)0;
318 c = ptr[idx++];
319 if (c == '\n' || c == '\r')
320 break;
321 }
322 ptr [idx] = '\0';
323 return ptr;
324 }
325 #endif /* 0 */
326
327
328 int
macwrite(int fd,void * ptr,unsigned len)329 macwrite (int fd, void *ptr, unsigned len)
330 {
331 long amt = len;
332
333 if (IsHandleFile (fd)) return -1;
334 if (FSWrite(fd, &amt, ptr) == noErr)
335 return (amt);
336 else
337 return (-1);
338 }
339
340
341 long
macseek(int fd,long where,short whence)342 macseek (int fd, long where, short whence)
343 {
344 short posMode;
345 long curPos;
346
347 if (IsHandleFile (fd)) {
348 return SetHandleFilePos (fd, whence, where);
349 }
350
351 switch (whence) {
352 default :
353 posMode = fsFromStart;
354 break;
355 case SEEK_CUR :
356 posMode = fsFromMark;
357 break;
358 case SEEK_END :
359 posMode = fsFromLEOF;
360 break;
361 }
362
363 if (SetFPos(fd, posMode, where) == noErr && GetFPos(fd, &curPos) == noErr)
364 return (curPos);
365 else
366 return(-1);
367 }
368
369
370 int
macunlink(const char * name)371 macunlink(const char *name)
372 {
373 Str255 pname;
374
375
376 C2P(name, pname);
377 return (HDelete(theDirs.dataRefNum, theDirs.dataDirID, pname) == noErr ? 0 : -1);
378 }
379
380
381
382 /* ---------------------------------------------------------------------- */
383
rsrc_dlb_init(void)384 boolean rsrc_dlb_init(void) {
385 return TRUE;
386 }
387
rsrc_dlb_cleanup(void)388 void rsrc_dlb_cleanup(void) {
389 }
390
rsrc_dlb_fopen(dlb * dp,const char * name,const char * mode)391 boolean rsrc_dlb_fopen(dlb *dp, const char *name, const char *mode) {
392 #if defined(__SC__) || defined(__MRC__)
393 # pragma unused(mode)
394 #endif
395 Str255 pname;
396
397 C2P(name, pname);
398 dp->fd = OpenHandleFile(pname, 'File'); /* automatically read-only */
399 return dp->fd >= 0;
400 }
401
rsrc_dlb_fclose(dlb * dp)402 int rsrc_dlb_fclose(dlb *dp) {
403 return CloseHandleFile(dp->fd);
404 }
405
rsrc_dlb_fread(char * buf,int size,int quan,dlb * dp)406 int rsrc_dlb_fread(char *buf, int size, int quan, dlb *dp) {
407 int nread;
408
409 if (size < 0 || quan < 0) return 0;
410 nread = ReadHandleFile(dp->fd, buf, (unsigned)size * (unsigned)quan);
411
412 return nread/size; /* # of whole pieces (== quan in normal case) */
413 }
414
rsrc_dlb_fseek(dlb * dp,long pos,int whence)415 int rsrc_dlb_fseek(dlb *dp, long pos, int whence) {
416 return SetHandleFilePos(dp->fd, whence, pos);
417 }
418
rsrc_dlb_fgets(char * buf,int len,dlb * dp)419 char *rsrc_dlb_fgets(char *buf, int len, dlb *dp) {
420 HandleFile *hfp = IsHandleFile(dp->fd);
421 char *p;
422 int bytesLeft, n = 0;
423
424 if (hfp && hfp->mark < hfp->size) {
425 bytesLeft = hfp->size - hfp->mark;
426 if (bytesLeft < len)
427 len = bytesLeft;
428
429 HLock(hfp->data);
430 for (n = 0, p = *hfp->data+hfp->mark; n < len; n++, p++) {
431 buf[n] = *p;
432 if (*p == '\r') buf[n] = '\n';
433 if (buf[n] == '\n') {
434 n++; /* we want the return in the buffer */
435 break;
436 }
437 }
438 HUnlock(hfp->data);
439
440 hfp->mark += n;
441 if (n != 0)
442 buf[n] = '\0'; /* null terminate result */
443 }
444
445 return n ? buf : NULL;
446 }
447
rsrc_dlb_fgetc(dlb * dp)448 int rsrc_dlb_fgetc(dlb *dp) {
449 HandleFile *hfp = IsHandleFile(dp->fd);
450 int ret;
451
452 if (!hfp || hfp->size <= hfp->mark) return EOF;
453
454 ret = *(unsigned char *)(*hfp->data + hfp->mark);
455 hfp->mark++;
456 return ret;
457 }
458
rsrc_dlb_ftell(dlb * dp)459 long rsrc_dlb_ftell(dlb *dp) {
460 HandleFile *hfp = IsHandleFile(dp->fd);
461
462 if (!hfp) return 0;
463 return hfp->mark;
464 }
465
466