/****************************************************************/ /* */ /* dosnames.c */ /* DOS-C */ /* */ /* Generic parsing functions for file name specifications */ /* */ /* Copyright (c) 1994 */ /* Pasquale J. Villani */ /* All Rights Reserved */ /* */ /* This file is part of DOS-C. */ /* */ /* DOS-C 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 */ /* 2, or (at your option) any later version. */ /* */ /* DOS-C 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. */ /* */ /* You should have received a copy of the GNU General Public */ /* License along with DOS-C; see the file COPYING. If not, */ /* write to the Free Software Foundation, 675 Mass Ave, */ /* Cambridge, MA 02139, USA. */ /* */ /****************************************************************/ #include "../../hdr/portab.h" /* $Logfile: D:/dos-c/src/fs/dosnames.c_v $ */ #ifndef IPL static BYTE *dosnamesRcsId = "$Header: D:/dos-c/src/fs/dosnames.c_v 1.4 29 May 1996 21:15:12 patv $"; #endif /* * $Log: D:/dos-c/src/fs/dosnames.c_v $ * * Rev 1.4 29 May 1996 21:15:12 patv * bug fixes for v0.91a * * Rev 1.3 19 Feb 1996 3:20:08 patv * Added NLS, int2f and config.sys processing * * Rev 1.2 01 Sep 1995 17:48:44 patv * First GPL release. * * Rev 1.1 30 Jul 1995 20:50:26 patv * Eliminated version strings in ipl * * Rev 1.0 02 Jul 1995 8:05:56 patv * Initial revision. * */ #include "globals.h" #define PathSep(c) ((c)=='/'||(c)=='\\') #define DriveChar(c) (((c)>='A'&&(c)<='Z')||((c)>='a'&&(c)<='z')) static BOOL bFileChar(UCOUNT uChar); VOID XlateLcase (BYTE *szFname, COUNT nChars); VOID DosTrimPath (BYTE FAR *lpszPathNamep); static BOOL bFileChar(UCOUNT uChar) { BYTE *pszValChar = ".\"/\\[]:|<>+=;,", *pszPtr; /* Null is not a valid character */ if(NULL == uChar) return FALSE; /* Loop through invalid character set */ for (pszPtr = pszValChar; *pszPtr != NULL; pszPtr++) if(uChar == *pszPtr) return FALSE; /* Not in excluded set, it's ok. */ return TRUE; } /* Should be converted to a portable version after v1.0 is released. */ VOID XlateLcase (BYTE *szFname, COUNT nChars) { while(nChars--) { if(*szFname >= 'a' && *szFname <= 'z') *szFname -= ('a' - 'A'); ++szFname; } } /* "Sometimes a cigar is just a cigar" - Sigmund Freud */ COUNT DosNames(BYTE FAR *lpszFileName, struct dosnames FAR *lpDosname) { COUNT nCharCount; BYTE FAR *lpszPath, FAR *lpszPathSep; BYTE FAR *lpszWork; /* Initialize the structure */ lpDosname -> dn_drive = default_drive; *lpDosname -> dn_network = *lpDosname -> dn_path = *lpDosname -> dn_name = '\0'; lpszPath = lpDosname -> dn_path; /* Start by cheking for a drive specifier ... */ if(DriveChar(*lpszFileName) && ':' == lpszFileName[1]) { /* found a drive, fetch it and bump pointer past drive */ lpDosname -> dn_drive = *lpszFileName - 'A'; if(lpDosname -> dn_drive > 26) lpDosname -> dn_drive -= ('a' - 'A'); lpszFileName += 2; } /* or for a network name specifier */ else if ('\\' == lpszFileName[1]) { /* bump past network '\\' specifier */ lpszFileName += 2; /* and copy network name */ for(lpszWork = lpDosname -> dn_network, nCharCount = 0; nCharCount < NAMEMAX && bFileChar(*lpszFileName) && !PathSep(*lpszFileName); ++nCharCount) { *lpszWork++ = *lpszFileName++; *lpszWork = '\0'; } } /* Loop through the name we got until a null terminator */ for(nCharCount = 0, lpszPath = lpszWork = lpDosname -> dn_path; nCharCount < NAMEMAX; ++nCharCount) { if(!bFileChar(*lpszFileName) && !PathSep(*lpszFileName) && '.' != *lpszFileName) break; /* Mark the path seperator for later use. We need to */ /* split the file and the path later, so we always mark */ /* last place we saw one. */ /* NB: we mark the path because we're going to null */ /* terminate there later */ if(PathSep(*lpszFileName)) { lpszWork = lpszPath; *lpszPath++ = '\\'; ++lpszFileName; } else *lpszPath++ = *lpszFileName++; } *lpszPath = '\0'; /* Now that we got the path, let's seperate the file name from */ /* the dir name. */ if(lpDosname -> dn_path == lpszWork) { /* We never moved off the path, either it starts from */ /* root and has only a file or it's just a specifier */ /* for root. It may also be a null */ if(NULL == *lpDosname -> dn_path) return SUCCESS; if('\\' == *lpDosname -> dn_path) { if(NULL == lpDosname -> dn_path[1]) /* Done, just exit */ return SUCCESS; /* copy the file name and return */ fstrncpy(lpDosname -> dn_name, (lpDosname -> dn_path + 1), FNAME_SIZE + FEXT_SIZE + 1); lpDosname -> dn_path[1] = NULL; return SUCCESS; } else { /* just a file specifier, make the path '.' */ fstrncpy(lpDosname -> dn_name, lpDosname -> dn_path, FNAME_SIZE + FEXT_SIZE + 1); fstrncpy(lpDosname -> dn_path, (BYTE FAR *)".", 1); return SUCCESS; } } else { /* Copy out the name and put a null in at the last */ /* place we saw a seperator. */ *lpszWork++ = NULL; fstrncpy(lpDosname -> dn_name, lpszWork, FNAME_SIZE + FEXT_SIZE + 1); /* Clean up before leaving */ DosTrimPath(lpDosname -> dn_path); return SUCCESS; } } BOOL IsDevice (BYTE *pszFileName) { struct dosnames Dosname; COUNT nLen = min(strlen(pszFileName),8); REG struct dhdr FAR *dhp = (struct dhdr FAR *)&nul_dev; /* break up the name first */ DosNames((BYTE FAR *)pszFileName, (struct dosnames FAR *)&Dosname); /* Test 1 - does it start with a \dev or /dev */ if((fstrcmp(Dosname.dn_name, (BYTE FAR *)"/dev") == 0) || (fstrcmp(Dosname.dn_name, (BYTE FAR *)"\\dev") == 0)) return TRUE; /* Test 2 - is it on the device chain? */ for(; -1l != (LONG)dhp; dhp = dhp -> dh_next) { BYTE cBuffer[8]; COUNT nIdx; /* Skip if block device */ if(!(dhp -> dh_attr & ATTR_CHAR)) continue; /* copy to cBuffer and space fill */ for(nIdx = 0; Dosname.dn_name[nIdx] != '.' && nIdx < nLen; ++nIdx) cBuffer[nIdx] = Dosname.dn_name[nIdx]; for(; nIdx > 8; ++nIdx) cBuffer[nIdx] = ' '; /* now compare */ if(fstrncmp((BYTE FAR *)cBuffer, dhp -> dh_name, 8) == 0) return TRUE; } return FALSE; } VOID DosTrimPath (BYTE FAR *lpszPathNamep) { BYTE FAR *lpszLast, FAR *lpszNext; COUNT nChars, flDotDot; for(lpszLast = lpszNext = lpszPathNamep, nChars = 0; *lpszNext != '\0' && nChars < NAMEMAX; ) { /* Initialize flag for loop. */ flDotDot = FALSE; /* If we are at a path seperator, check for extra path */ /* seperator, '.' and '..' to reduce. */ if(*lpszNext == '\\') { /* If it's '\', just move everything down one. */ if(*(lpszNext + 1) == '\\') fstrncpy(lpszNext, lpszNext + 1, NAMEMAX); /* also ckech for '.' and '..' and move down */ /* as appropriate. */ else if(*(lpszNext + 1) == '.') { if(*(lpszNext + 2) == '.' && *(lpszNext + 3) == '\\') { fstrncpy(lpszLast, lpszNext + 3, NAMEMAX); /* bump back to the last */ /* seperator. */ lpszNext = lpszLast; /* set lpszLast to the last one */ if(lpszLast <= lpszPathNamep) continue; do { --lpszLast; } while(lpszLast != lpszPathNamep && *lpszLast != '\\'); flDotDot = TRUE; } /* Note: we skip strange stuff that */ /* starts with '.' */ else if(*(lpszNext + 2) == '\\') { fstrncpy(lpszNext, lpszNext + 2, NAMEMAX); } /* If we're at theend of a string, just */ /* exit. */ else if(*(lpszNext + 2) == NULL) return; } else { /* No '.' or '\' so mark it and bump */ /* past */ lpszLast = lpszNext++; continue; } /* Done. Now set last to next to mark this */ /* instance of path seperator. */ if(!flDotDot) lpszLast = lpszNext; } else /* For all other cases, bump lpszNext for the */ /* next check */ ++lpszNext; } }