Metropoli BBS
VIEWER: dosnames.c MODE: TEXT (ASCII)
/****************************************************************/
/*								*/
/*			   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;
	}
}

[ RETURN TO DIRECTORY ]