/* Copyright 2015 Wolfgang Thaller. This file is part of Retro68. Retro68 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Retro68 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING and COPYING.RUNTIME respectively. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include void *_sbrk_r(struct _reent *reent, ptrdiff_t increment) { Debugger(); return NewPtrClear(increment); } __attribute__((weak)) void _exit(int status) { //if(status != 0) // Debugger(); ExitToShell(); for(;;) ; } ssize_t _consolewrite(int fd, const void *buf, size_t count); ssize_t _consoleread(int fd, void *buf, size_t count); const int kMacRefNumOffset = 10; static int OSErrToErrno(OSErr err) { switch (err) { case noErr: return 0; case nsvErr: return ENODEV; case fnfErr: case dirNFErr: return ENOENT; case bdNamErr: case paramErr: return EINVAL; case ioErr: default: return EIO; } } ssize_t _write_r(struct _reent *reent, int fd, const void *buf, size_t count) { long cnt = count; if(fd >= kMacRefNumOffset) { FSWrite(fd - kMacRefNumOffset, &cnt, buf); return cnt; } else return _consolewrite(fd,buf,count); } ssize_t _read_r(struct _reent *reent, int fd, void *buf, size_t count) { long cnt = count; if(fd >= kMacRefNumOffset) { FSRead(fd - kMacRefNumOffset, &cnt, buf); return cnt; } else return _consoleread(fd,buf,count); } int _open_r(struct _reent *reent, const char* name, int flags, int mode) { Str255 pname; #if TARGET_API_MAC_CARBON // Carbon has the new, sane version. c2pstrcpy(pname,name); #else // It is also available in various glue code libraries and // in some versions of InterfaceLib, but it's confusing. // Using the inplace variant, c2pstr, isn't much better than // doing things by hand: strncpy(&pname[1],name,255); pname[0] = strlen(name); #endif short ref; SInt8 permission; switch(flags & O_ACCMODE) { case O_RDONLY: permission = fsRdPerm; break; case O_WRONLY: permission = fsWrPerm; break; case O_RDWR: permission = fsRdWrPerm; break; } if(flags & O_CREAT) { HCreate(0,0,pname,'????','TEXT'); } OSErr err = HOpenDF(0,0,pname,fsRdWrPerm,&ref); if(err == paramErr) err = HOpen(0,0,pname,fsRdWrPerm,&ref); if(err) return -1; // TODO: errno if(flags & O_TRUNC) { SetEOF(ref, 0); } return ref + kMacRefNumOffset; } int _close_r(struct _reent *reent, int fd) { if(fd >= kMacRefNumOffset) { short refNum = fd - kMacRefNumOffset; short vRefNum; OSErr err = GetVRefNum(refNum, &vRefNum); FSClose(refNum); if (err == noErr) FlushVol(NULL, vRefNum); } return 0; } int _fstat_r(struct _reent *reent, int fd, struct stat *buf) { const long long int epochDiffInSeconds = 2082844800LL; if (buf == NULL) { reent->_errno = EFAULT; return -1; } memset(buf, 0, sizeof (struct stat)); buf->st_nlink = 1; buf->st_uid = 42; buf->st_gid = 42; buf->st_blksize = 512; if (fd < kMacRefNumOffset) { // Console. unsigned long secs; GetDateTime(&secs); buf->st_mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP; buf->st_mtim.tv_sec = secs - epochDiffInSeconds; buf->st_ctim.tv_sec = secs - epochDiffInSeconds; buf->st_atim.tv_sec = secs - epochDiffInSeconds; return 0; } CInfoPBRec p; memset(&p, 0, sizeof (p)); p.hFileInfo.ioFRefNum = fd - kMacRefNumOffset; OSErr err = PBGetCatInfoSync(&p); if (err) { reent->_errno = OSErrToErrno(err); return -1; } ino_t inode; mode_t mode; long long mtim; long long ctim; int size = 0; int phySize = 0; if (p.hFileInfo.ioFlAttrib & 16) { inode = p.dirInfo.ioDrDirID; mode = S_IFDIR | S_IRUSR | S_IRUSR | S_IXUSR; mtim = p.dirInfo.ioDrMdDat - epochDiffInSeconds; ctim = p.dirInfo.ioDrCrDat - epochDiffInSeconds; } else { inode = p.hFileInfo.ioDirID; mode = S_IFREG | S_IRUSR | S_IRUSR; mtim = p.hFileInfo.ioFlMdDat - epochDiffInSeconds; ctim = p.hFileInfo.ioFlCrDat - epochDiffInSeconds; size = p.hFileInfo.ioFlLgLen; phySize = p.hFileInfo.ioFlPyLen + p.hFileInfo.ioFlRPyLen; } HParamBlockRec h; memset(&h, 0, sizeof (h)); h.volumeParam.ioVRefNum = p.hFileInfo.ioVRefNum; err = PBHGetVInfoSync(&h); if (err) { reent->_errno = OSErrToErrno(err); return -1; } buf->st_dev = h.volumeParam.ioVDrvInfo; buf->st_ino = inode; buf->st_mode = mode; buf->st_size = size; buf->st_mtim.tv_sec = mtim; buf->st_ctim.tv_sec = ctim; buf->st_blocks = (phySize / 512) + (phySize % 512 > 0); return 0; } extern int _stat_r(struct _reent * reent, const char *fn, struct stat *buf) { return -1; } off_t _lseek_r(struct _reent *reent, int fd, off_t offset, int whence) { if(fd >= kMacRefNumOffset) { short posMode; switch(whence) { case SEEK_SET: posMode = fsFromStart; break; case SEEK_CUR: posMode = fsFromMark; break; case SEEK_END: posMode = fsFromLEOF; break; } short ref = fd - kMacRefNumOffset; SetFPos(ref, posMode, offset); long finalPos; GetFPos(ref, &finalPos); return finalPos; } return (off_t) -1; } int _kill_r(struct _reent *reent, pid_t pid, int sig) { if(pid == 42) _exit(42); else return -1; } pid_t _getpid_r(struct _reent *reent) { return 42; } int _fork_r(struct _reent *reent) { return -1; } int _execve_r(struct _reent *reent, const char *fn, char *const * argv, char *const *envp) { return -1; } int _fcntl_r(struct _reent *reent, int fd, int cmd, int arg) { return -1; } int _isatty_r(struct _reent *reent, int fd) { return fd < kMacRefNumOffset; } int _link_r(struct _reent *reent, const char *from, const char *to) { reent->_errno = EPERM; return -1; } int _mkdir_r(struct _reent *reent, const char *fn, int mode) { return -1; } int _rename_r(struct _reent *reent, const char *from, const char *to) { return -1; } int _unlink_r(struct _reent *reent, const char *fn) { return -1; } _CLOCK_T_ _times_r(struct _reent *reent, struct tms *buf) { reent->_errno = EACCES; return -1; } int _wait_r(struct _reent *reent, int *wstatus) { reent->_errno = ECHILD; return -1; /* Always fails */ } int _gettimeofday_r(struct _reent *reent, struct timeval *tp, void *__tz) { /* Classic MacOS's GetDateTime function returns an integer. * TickCount() has a slightly higher resolution, but is independent of the real-time clock. */ unsigned long secs; GetDateTime(&secs); unsigned long ticks = TickCount(); static unsigned long savedTicks = 0, savedSecs = 0; if(!savedSecs) { savedTicks = ticks; savedSecs = secs; } else { unsigned long elapsedTicks = ticks - savedTicks; unsigned long elapsedSecs = secs - savedSecs; unsigned long expectedTicks = elapsedSecs * 60 + elapsedSecs * 3 / 20; if(expectedTicks > elapsedTicks) savedTicks = ticks; else savedTicks += expectedTicks; savedSecs = secs; } if(tp) { const int epochDifferenceInYears = 1970 - 1904; const int epochDifferenceInDays = 365 * epochDifferenceInYears + (epochDifferenceInYears + 3)/ 4; // round up for leap years tp->tv_sec = secs - 86400 * epochDifferenceInDays; tp->tv_usec = (ticks - savedTicks) * 20000000 / 2003; } return 0; } extern int _getentropy_r (struct _reent *, void *, size_t) { errno = ENOSYS; return -1; }