📄 fsiface.cpp
字号:
//**************************************************************************// MODULE : Process File System Support Object Methods. *// AUTHOR : Ron Chernich *// PURPOSE: Each Process descriptor has a pointer to one of these. If the *// the process ever invokes an ASSIGN file function, an instance *// of this class is created to support all required actions. *// HISTORY: *// 31-AUG-94 First Simple implementation. *// 11-SEP-94 Relief! Unit tests for all basic PLL/2 file funcs passed! *//************************************************************************** #include <ctype.h> #include "fsiface.hpp" #undef toupper // ensure the function version (not macro) is used ////////////////////////////////////////////////////////////////////////// When created, simply ensure that all XFCB pointers are NULL and set// the "magic" number to one sufficiently random to assure that they// will appear unique..//FsIface::FsIface (UINT16 n, Knl *p) : pTx(p), uID(n){ for (int idx = 0; idx < MAX_FILES; idx++) pXfcb[idx] = NULL; uMagic = (UINT16)(Clock.GetTicks() & 0x0ff0);}//////////////// on destruction, any remaining XFCB's are destroyed without// flushing (ie automatic behavour assumes process went illegal)..//FsIface::~FsIface (void){ for (int idx = 0; idx < MAX_FILES; idx++) if (NULL == pXfcb[idx]) break; else { if (pXfcb[idx]->Fcb.pBuf) DELETE_ARRAY pXfcb[idx]->Fcb.pBuf; delete pXfcb[idx]; }}////////////// Copies passed "name" string into passed destination, doing wild card expansion of// first encountered *splat*, padding to the passed length..// RETURNS: TRUE .. all ok// FALSE .. bad char, too much input, etc, etc//BOOL FsIface::ExpandName (char *pszTarg, char *pszSrc, UINT16 nLen){ if (strchr(pszSrc, ':') || strchr(pszSrc, '.') || strchr(pszSrc, ':')) return FALSE; if (strlen(pszSrc) > nLen) return FALSE; char *cp = pszSrc; for (UINT16 idx = 0; idx < nLen; idx++) if ('\0' == *cp) pszTarg[idx] = ' '; else if (*cp != '*') pszTarg[idx] = toupper(*cp++); else { pszTarg[idx] = '?'; *cp = '\0'; } return TRUE;}////////////////////// If the passed path is for a valid drive unit and the name pases ok,// try to get an XFCB for it//// RETURNS: TRUE .. all Ok// FALSE .. Bad file name or disk unit//UINT16 FsIface::Allocate (HANDLE& hFile, char *pszName){ int idx; char *cp1, *cp2, *psz; for (idx = 0; idx < MAX_FILES; idx++) if (NULL == pXfcb[idx]) break; if (idx < MAX_FILES) { pXfcb[idx] = new XFCB; if (NULL == pXfcb[idx]) return FS_Fail; memset((char*)pXfcb[idx], 0, sizeof(XFCB)); pXfcb[idx]->Fcb.pBuf = new char[BLOCK_LEN]; if (NULL == pXfcb[idx]->Fcb.pBuf) { delete pXfcb[idx]; return FS_Fail; } if (cp2 = strrchr(pszName, '.')) *cp2++ = '\0'; if (NULL == (cp1 = strchr(pszName, ':'))) cp1 = pszName; else { *cp1++ = '\0'; if (strlen(pszName) > 1) return FS_BadUnit; *pszName = toupper(*pszName); if ((*pszName < 'A') || (*pszName > 'A' + MAX_DRIVES)) return FS_BadUnit; pXfcb[idx]->Fcb.de.nUsrNmbr = *pszName - 'A'; } if (0 == strlen(cp1)) return FS_BadName; psz = (char*)pXfcb[idx]->Fcb.de.fname; if (FALSE == ExpandName(psz, cp1, PNAME_LEN)) return FS_BadName; psz = (char*)pXfcb[idx]->Fcb.de.fextn; if (FALSE == ExpandName(psz, cp2, ENAME_LEN)) return FS_BadName; hFile = (HANDLE)(uMagic + idx); pXfcb[Idx(hFile)]->mState = FSM_Assigned; return FS_Ok; } return FS_NoHandles;}///////////////////// This func (which will always cause a block), posts a message to open// an existing file if the current state is "Assigned" then waits to see// if the open works (the file may not exist, you see)..//UINT16 FsIface::Open (HANDLE hFile, UINT16 uStat){ if ((0 <= Idx(hFile)) && (Idx(hFile) < MAX_FILES) && (pXfcb[Idx(hFile)])) switch (pXfcb[Idx(hFile)]->mState) { case FSM_Assigned: { PFCBREF pRef = new FCBREF; pRef->pFcbRef = (FCB*)&pXfcb[Idx(hFile)]->Fcb; message Msg(uID, FS_Open, 0, (void*)pRef); pTx->PostMsg(ID_FS, &Msg); pXfcb[Idx(hFile)]->mState = FSM_Opening; return FS_Busy; } break; case FSM_Opening: switch (uStat) { case FS_Ok: pXfcb[Idx(hFile)]->mState = FSM_BufferMT; break; case FS_NotFound: pXfcb[Idx(hFile)]->mState = FSM_Assigned; break; default: uStat = FS_Fail; } return uStat; } return FS_Fail;}////////////////////// This scenario deals adequately with a CLOSE call, flushing the file if// there have been any write operations performed, in which case we transit// to the intermediate "Flushing" state, return Busy and wait for the result// to come back. When it does (or if there have been no writes, or even// possibly we never got past "assigned"), we deallocate the XFCB for reuse.//// An EOF mark is inserted in the last block unless we are right on the// point of opening a new record (in which case the BDOS can report the EOF).//UINT16 FsIface::Close (HANDLE hFile, UINT16 uStat){ if ((Idx(hFile) < MAX_FILES) && (pXfcb[Idx(hFile)])) switch (pXfcb[Idx(hFile)]->mState) { case FSM_BufferMT: case FSM_DataAvailable: if (0 == pXfcb[Idx(hFile)]->nWriteCnt) { pXfcb[Idx(hFile)]->mState = FSM_Closing; return Close(hFile, uStat); } case FSM_BuffAvailable: pXfcb[Idx(hFile)]->mState = FSM_Flushing; return Write(hFile, (char)FS_EOFmark); case FSM_Writing: if (FS_Ok == uStat) { PFCBREF pRef = new FCBREF; pRef->pFcbRef = (FCB*)&pXfcb[Idx(hFile)]->Fcb; message Msg(uID, FS_Close, 0, (void*)pRef); pTx->PostMsg(ID_FS, &Msg); pXfcb[Idx(hFile)]->mState = FSM_Closing; return FS_Busy; } pXfcb[Idx(hFile)]->mState = FSM_DiskError; break; case FSM_Closing: DELETE_ARRAY pXfcb[Idx(hFile)]->Fcb.pBuf; delete pXfcb[Idx(hFile)]; pXfcb[Idx(hFile)] = NULL; break; default: uStat = FS_Fail; } return uStat;}////////////////////// Allow deletes provided no operation other than Allocate has taken place.// Regardless of outcome, status is set back to "Assigned" ('cause the PLL/2// compiler always fires off a "Delete" ahead of a "Creat" to enforce the// rules for the "ASSIGN, REWRITE" precodures)..//UINT16 FsIface::Delete (HANDLE hFile, UINT16 uStat){ if ((Idx(hFile) < MAX_FILES) && (pXfcb[Idx(hFile)])) switch (pXfcb[Idx(hFile)]->mState) { case FSM_Assigned: { PFCBREF pRef = new FCBREF; pRef->pFcbRef = (FCB*)&pXfcb[Idx(hFile)]->Fcb; message Msg(uID, FS_Delete, 0, (void*)pRef); pTx->PostMsg(ID_FS, &Msg); pXfcb[Idx(hFile)]->mState = FSM_Deleting; } return FS_Busy; case FSM_Deleting: pXfcb[Idx(hFile)]->mState = FSM_Assigned; if (FS_Ok == uStat) return FS_Ok; else return FS_NotFound; } return FS_Fail;}////////////////////// If we hit here with status of Assigned, we try to create a new file,// (provided the FCB name has no wild chars int it, which is bad, but we// couldn't tell if the ASSIGN would be followed by a RESET or a REWRITE)// by sending a message to the BDOS and telling exec this process is now// blocked (busy). When the reply comes back, we transit to "Buffer Empty"// ready for a read or write sequence (can't tell which yet) if the creat// worked and return the status to the caller (normally the PCI).//UINT16 FsIface::Creat (HANDLE hFile, UINT16 uStat){ if ((Idx(hFile) < MAX_FILES) && (pXfcb[Idx(hFile)])) switch (pXfcb[Idx(hFile)]->mState) { case FSM_Assigned: { char *cp = (char*)pXfcb[Idx(hFile)]->Fcb.de.fname; for (int i = 0; i < FILENAME_LEN; i++, cp++) if ('?' == *cp) return FS_BadName; PFCBREF pRef = new FCBREF; pRef->pFcbRef = (FCB*)&pXfcb[Idx(hFile)]->Fcb; message Msg(uID, FS_Creat, 0, (void*)pRef); pTx->PostMsg(ID_FS, &Msg); pXfcb[Idx(hFile)]->mState = FSM_Creating; return FS_Busy; } case FSM_Creating: pXfcb[Idx(hFile)]->mState = (FS_Ok == uStat) ? FSM_BufferMT : FSM_DiskFull; return uStat; } return FS_Fail;}////////////////////// Provided we have a valid file handle, with an existing extended control block// which has not been "written to", read a character, performing buffered reads// to the BDOS. We will assume that EOF marks (usually 0x1a) are imbedded in all// text files. NOTE how we use a little gentle recursion to simplify the code..//UINT16 FsIface::Read (HANDLE hFile, char& ch, UINT16 uStat){ if ((MAX_FILES <= Idx(hFile)) || (NULL == pXfcb[Idx(hFile)]) || (pXfcb[Idx(hFile)]->nWriteCnt)) return FS_Fail; switch (pXfcb[Idx(hFile)]->mState) { case FSM_BufferMT: { PFCBREF pRef = new FCBREF; pRef->pFcbRef = (FCB*)&pXfcb[Idx(hFile)]->Fcb; message Msg(uID, FS_ReadSeq, 0, (void*)pRef); pTx->PostMsg(ID_FS, &Msg); pXfcb[Idx(hFile)]->mState = FSM_Reading; pXfcb[Idx(hFile)]->nReadCnt++; } return FS_Busy; case FSM_Reading: pXfcb[Idx(hFile)]->mState = FSM_DataAvailable; pXfcb[Idx(hFile)]->ndx = 0; return Read(hFile, ch, uStat); case FSM_DataAvailable: if (BLOCK_LEN <= pXfcb[Idx(hFile)]->ndx) { pXfcb[Idx(hFile)]->mState = FSM_BufferMT; return Read(hFile, ch, uStat); } else { ch = pXfcb[Idx(hFile)]->Fcb.pBuf[pXfcb[Idx(hFile)]->ndx++]; if ((BLOCK_LEN > pXfcb[Idx(hFile)]->ndx) && (FS_EOFmark == pXfcb[Idx(hFile)]->Fcb.pBuf[pXfcb[Idx(hFile)]->ndx])) pXfcb[Idx(hFile)]->mState = FSM_EOF; } return FS_Ok; case FSM_EOF: return FS_Fail; } return uStat;}////////////////////// Buffer character writes, flushing to disk as it fills. The handle must be// valid, an extended FCB allocated and the file can NOT have been read from.// Again, we use recursion to save on code as the State Machine steps through// the sequence BufferMT -> BuffAvailable -> Writing -> BufferMT..//// Caution! BufferMT FALLS THROUGH to BuffAvailable//UINT16 FsIface::Write (HANDLE hFile, char ch, UINT16 uStat){ if ((Idx(hFile) < MAX_FILES) && (pXfcb[Idx(hFile)]) && (0 == pXfcb[Idx(hFile)]->nReadCnt)) switch (pXfcb[Idx(hFile)]->mState) { case FSM_BufferMT: pXfcb[Idx(hFile)]->nWriteCnt++; pXfcb[Idx(hFile)]->ndx = 0; pXfcb[Idx(hFile)]->mState = FSM_BuffAvailable; case FSM_Flushing: case FSM_BuffAvailable: { if (pXfcb[Idx(hFile)]->ndx < BLOCK_LEN) { pXfcb[Idx(hFile)]->Fcb.pBuf[pXfcb[Idx(hFile)]->ndx++] = ch; if (FSM_Flushing != pXfcb[Idx(hFile)]->mState) return FS_Ok; } PFCBREF pRef = new FCBREF; pRef->pFcbRef = (FCB*)&pXfcb[Idx(hFile)]->Fcb; message Msg(uID, FS_WriteSeq, 0, (void*)pRef); pTx->PostMsg(ID_FS, &Msg); pXfcb[Idx(hFile)]->mState = FSM_Writing; } return FS_Busy; case FSM_Writing: if (uStat != FS_Ok) { pXfcb[Idx(hFile)]->mState = FSM_DiskFull; return FS_Fail; } pXfcb[Idx(hFile)]->mState = FSM_BufferMT; return Write(hFile, ch, uStat); } return FS_Fail;}////////////////////// This one deals with entering strings into the deblocking buffer. It is// similar to the signle char case except it does not have to deal with the// "FSM_Flushing" state, but it does have to deal with an input string that// may fill the buffer (perhaps more than once!). The XFCB has a char// pointer to hold any overflow. A copy of this overflow is held using// this reference and the buffer written to disk. When the caller (who// has managed the blocked state) call us again, we test this pointer// and recurse until is is null.//UINT16 FsIface::Write (HANDLE hFile, char *psz, UINT16 uStat){ if (psz && (Idx(hFile) < MAX_FILES) && (pXfcb[Idx(hFile)]) && (0 == pXfcb[Idx(hFile)]->nReadCnt)) switch (pXfcb[Idx(hFile)]->mState) { case FSM_BufferMT: pXfcb[Idx(hFile)]->nWriteCnt++; pXfcb[Idx(hFile)]->ndx = 0; pXfcb[Idx(hFile)]->mState = FSM_BuffAvailable; case FSM_BuffAvailable: { char *pszHold = NULL; while (*psz && (pXfcb[Idx(hFile)]->ndx < BLOCK_LEN)) pXfcb[Idx(hFile)]->Fcb.pBuf[pXfcb[Idx(hFile)]->ndx++] = *psz++; if (*psz) { pszHold = new char[strlen(psz) + 1]; if (pszHold) strcpy(pszHold, psz); else return FS_Fail; } if (pXfcb[Idx(hFile)]->pszTemp) DELETE_ARRAY pXfcb[Idx(hFile)]->pszTemp; pXfcb[Idx(hFile)]->pszTemp = pszHold; if (pXfcb[Idx(hFile)]->ndx < BLOCK_LEN) return FS_Ok; PFCBREF pRef = new FCBREF; pRef->pFcbRef = (FCB*)&pXfcb[Idx(hFile)]->Fcb; message Msg(uID, FS_WriteSeq, 0, (void*)pRef); pTx->PostMsg(ID_FS, &Msg); pXfcb[Idx(hFile)]->mState = FSM_Writing; } return FS_Busy; case FSM_Writing: if (uStat != FS_Ok) { pXfcb[Idx(hFile)]->mState = FSM_DiskFull; return FS_Fail; } pXfcb[Idx(hFile)]->mState = FSM_BufferMT; return (NULL == pXfcb[Idx(hFile)]->pszTemp) ? FS_Ok : Write(hFile, pXfcb[Idx(hFile)]->pszTemp, uStat); default: break; } return FS_Fail;}////////////////////// ** NOT IMPLEMENTED **//UINT16 FsIface::Read (HANDLE hFile, char *psz, UINT16 uStat){ return FS_Ok;}////////////////////// ** NOT IMPLEMENTED **////UINT16 FsIface::Stat (HANDLE, UINT16){ return FS_Ok;}////////////////////// Return the state of the the XFCB FSM associated with the passed handle// as either hit end of file, or not.//UINT16 FsIface::IsEof (HANDLE hFile){ return ((MAX_FILES <= Idx(hFile)) || (NULL == pXfcb[Idx(hFile)])) ? FS_Fail : (FSM_EOF == pXfcb[Idx(hFile)]->mState) ? FS_EOF : FS_Ok;}////////////////////// ** NOT IMPLEMENTED **//UINT16 FsIface::CloseAll (UINT16){ return FS_Ok;}////////////////////// ** NOT IMPLEMENTED **//UINT16 FsIface::FindFirst (HANDLE, UINT16){ return FS_Ok;}////////////////////// ** NOT IMPLEMENTED **//UINT16 FsIface::FindNext (HANDLE hFile, UINT16 uStat){ return FS_Ok;}/********************************** eof **********************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -