/****************************************************************/ /* */ /* 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 "portab.h" #ifdef VERSION_STRINGS static BYTE *dosnamesRcsId = "$Id$"; #endif /* * $Log$ * Revision 1.10 2001/07/22 01:58:58 bartoldeman * Support for Brian's FORMAT, DJGPP libc compilation, cleanups, MSCDEX * * Revision 1.9 2001/06/03 14:16:17 bartoldeman * BUFFERS tuning and misc bug fixes/cleanups (2024c). * * Revision 1.8 2001/04/15 03:21:50 bartoldeman * See history.txt for the list of fixes. * * Revision 1.7 2001/03/21 02:56:25 bartoldeman * See history.txt for changes. Bug fixes and HMA support are the main ones. * * Revision 1.6 2000/06/21 18:16:46 jimtabor * Add UMB code, patch, and code fixes * * Revision 1.5 2000/06/01 06:37:38 jimtabor * Read History for Changes * * Revision 1.4 2000/05/26 19:25:19 jimtabor * Read History file for Change info * * Revision 1.3 2000/05/25 20:56:21 jimtabor * Fixed project history * * Revision 1.2 2000/05/08 04:29:59 jimtabor * Update CVS to 2020 * * Revision 1.1.1.1 2000/05/06 19:34:53 jhall1 * The FreeDOS Kernel. A DOS kernel that aims to be 100% compatible with * MS-DOS. Distributed under the GNU GPL. * * Revision 1.2 2000/05/08 04:29:59 jimtabor * Update CVS to 2020 * * Revision 1.4 2000/03/31 05:40:09 jtabor * Added Eric W. Biederman Patches * * Revision 1.3 2000/03/09 06:07:11 kernel * 2017f updates by James Tabor * * Revision 1.2 1999/04/04 18:51:43 jprice * no message * * Revision 1.1.1.1 1999/03/29 15:41:54 jprice * New version without IPL.SYS * * Revision 1.4 1999/02/02 04:40:49 jprice * Steve Miller fixed a bug with doing "cd ." would lock the machine. * * Revision 1.3 1999/02/01 01:43:28 jprice * Fixed findfirst function to find volume label with Windows long filenames * * Revision 1.2 1999/01/22 04:15:28 jprice * Formating * * Revision 1.1.1.1 1999/01/20 05:51:00 jprice * Imported sources * * * Rev 1.8 22 Jan 1998 4:09:00 patv * Fixed pointer problems affecting SDA * * Rev 1.7 04 Jan 1998 23:14:38 patv * Changed Log for strip utility * * Rev 1.6 03 Jan 1998 8:36:04 patv * Converted data area to SDA format * * Rev 1.5 16 Jan 1997 12:46:36 patv * pre-Release 0.92 feature additions * * 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')) #define DirChar(c) (!strchr("\"[]:|<>+=;,", (c))) #define NameChar(c) (!strchr(".\"/\\[]:|<>+=;,*?", (c))) #define WildChar(c) (!strchr(".\"/\\[]:|<>+=;,", (c))) VOID XlateLcase(BYTE * szFname, COUNT nChars); VOID DosTrimPath(BYTE * lpszPathNamep); /* 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; } } VOID SpacePad(BYTE * szString, COUNT nChars) { REG COUNT i; for (i = strlen(szString); i < nChars; i++) szString[i] = ' '; } /* MSD durring an FindFirst search string looks like this; (*), & (.) == Current directory *.* (\) == Root directory *.* (..) == Back one directory *.* */ COUNT ParseDosName(BYTE * lpszFileName, COUNT * pnDrive, BYTE * pszDir, BYTE * pszFile, BYTE * pszExt, BOOL bAllowWildcards) { COUNT nDirCnt, nFileCnt, nExtCnt; BYTE *lpszLclDir, *lpszLclFile, *lpszLclExt; /* Initialize the users data fields */ if (pszDir) *pszDir = '\0'; if (pszFile) *pszFile = '\0'; if (pszExt) *pszExt = '\0'; lpszLclFile = lpszLclExt = lpszLclDir = 0; nDirCnt = nFileCnt = nExtCnt = 0; /* Start by cheking for a drive specifier ... */ if (DriveChar(*lpszFileName) && ':' == lpszFileName[1]) { /* found a drive, fetch it and bump pointer past drive */ /* NB: this code assumes ASCII */ if (pnDrive) { *pnDrive = *lpszFileName - 'A'; if (*pnDrive > 26) *pnDrive -= ('a' - 'A'); } lpszFileName += 2; } else { if (pnDrive) { *pnDrive = -1; } } if (!pszDir && !pszFile && !pszExt) return SUCCESS; /* Now see how long a directory component we have. */ lpszLclDir = lpszLclFile = lpszFileName; while (DirChar(*lpszFileName)) { if (PathSep(*lpszFileName)) lpszLclFile = lpszFileName + 1; ++lpszFileName; } nDirCnt = FP_OFF(lpszLclFile) - FP_OFF(lpszLclDir); /* Parse out the file name portion. */ lpszFileName = lpszLclFile; while (bAllowWildcards ? WildChar(*lpszFileName) : NameChar(*lpszFileName)) { ++nFileCnt; ++lpszFileName; } if (nFileCnt == 0) /* Lixing Yuan Patch */ if (bAllowWildcards) /* for find first */ { if (*lpszFileName == '.') lpszFileName++; if (*lpszFileName == '.') lpszFileName++; if (*lpszFileName != '\0') return DE_FILENOTFND; if (pszDir) { if ((lpszFileName - lpszLclFile) == 2) /* for tail DotDot */ nDirCnt += 2; if (nDirCnt > PARSE_MAX-1) nDirCnt = PARSE_MAX-1; bcopy(lpszLclDir, pszDir, nDirCnt); if (((lpszFileName - lpszLclFile) == 2) && (nDirCnt < PARSE_MAX)) pszDir[nDirCnt++] = '\\'; /* make DosTrimPath() enjoy, for tail DotDot */ pszDir[nDirCnt] = '\0'; DosTrimPath(pszDir); } if (pszFile) { *pszFile++ = '*'; *pszFile = '\0'; } if (pszExt) { *pszExt++ = '*'; *pszExt = '\0'; } return SUCCESS; } else return DE_FILENOTFND; /* Now we have pointers set to the directory portion and the */ /* file portion. Now determine the existance of an extension. */ lpszLclExt = lpszFileName; if ('.' == *lpszFileName) { lpszLclExt = ++lpszFileName; while (*lpszFileName) { if (bAllowWildcards ? WildChar(*lpszFileName) : NameChar(*lpszFileName)) { ++nExtCnt; ++lpszFileName; } else{ return DE_FILENOTFND; } } } else if (*lpszFileName) return DE_FILENOTFND; /* Fix lengths to maximums allowed by MS-DOS. */ if (nDirCnt > PARSE_MAX-1) nDirCnt = PARSE_MAX-1; if (nFileCnt > FNAME_SIZE) nFileCnt = FNAME_SIZE; if (nExtCnt > FEXT_SIZE) nExtCnt = FEXT_SIZE; /* Finally copy whatever the user wants extracted to the user's */ /* buffers. */ if (pszDir) { bcopy(lpszLclDir, pszDir, nDirCnt); pszDir[nDirCnt] = '\0'; } if (pszFile) { bcopy(lpszLclFile, pszFile, nFileCnt); pszFile[nFileCnt] = '\0'; } if (pszExt) { bcopy(lpszLclExt, pszExt, nExtCnt); pszExt[nExtCnt] = '\0'; } /* Clean up before leaving */ if (pszDir) DosTrimPath(pszDir); return SUCCESS; } #if 0 /* not necessary anymore because of truename */ COUNT ParseDosPath(BYTE * lpszFileName, COUNT * pnDrive, BYTE * pszDir, BYTE * pszCurPath) { COUNT nDirCnt, nPathCnt; BYTE *lpszLclDir, *pszBase = pszDir; /* Initialize the users data fields */ *pszDir = '\0'; lpszLclDir = 0; nDirCnt = nPathCnt = 0; /* Start by cheking for a drive specifier ... */ if (DriveChar(*lpszFileName) && ':' == lpszFileName[1]) { /* found a drive, fetch it and bump pointer past drive */ /* NB: this code assumes ASCII */ if (pnDrive) { *pnDrive = *lpszFileName - 'A'; if (*pnDrive > 26) *pnDrive -= ('a' - 'A'); } lpszFileName += 2; } else { if (pnDrive) { *pnDrive = -1; } } lpszLclDir = lpszFileName; if (!PathSep(*lpszLclDir)) { fstrncpy(pszDir, pszCurPath, PARSE_MAX - 1); /*TE*/ nPathCnt = fstrlen(pszCurPath); if (!PathSep(pszDir[nPathCnt - 1]) && nPathCnt < PARSE_MAX - 1) /*TE*/ pszDir[nPathCnt++] = '\\'; if (nPathCnt > PARSE_MAX) nPathCnt = PARSE_MAX; pszDir += nPathCnt; } /* Now see how long a directory component we have. */ while (NameChar(*lpszFileName) || PathSep(*lpszFileName) || '.' == *lpszFileName) { ++nDirCnt; ++lpszFileName; } /* Fix lengths to maximums allowed by MS-DOS. */ if ((nDirCnt + nPathCnt) > PARSE_MAX - 1) /*TE*/ nDirCnt = PARSE_MAX - 1 - nPathCnt; /* Finally copy whatever the user wants extracted to the user's */ /* buffers. */ if (pszDir) { bcopy(lpszLclDir, pszDir, nDirCnt); pszDir[nDirCnt] = '\0'; } /* Clean up before leaving */ DosTrimPath(pszBase); /* Before returning to the user, eliminate any useless */ /* trailing "\\." since the path prior to this is sufficient. */ nPathCnt = strlen(pszBase); if (2 == nPathCnt) /* Special case, root */ { if (!strcmp(pszBase, "\\.")) pszBase[1] = '\0'; } else if (2 < nPathCnt) { if (!strcmp(&pszBase[nPathCnt - 2], "\\.")) pszBase[nPathCnt - 2] = '\0'; } return SUCCESS; } #endif VOID DosTrimPath(BYTE * lpszPathNamep) { BYTE *lpszLast, *lpszNext, *lpszRoot = NULL; COUNT nChars, flDotDot; /* First, convert all '/' to '\'. Look for root as we scan */ if (*lpszPathNamep == '\\') lpszRoot = lpszPathNamep; for (lpszNext = lpszPathNamep; *lpszNext; ++lpszNext) { if (*lpszNext == '/') *lpszNext = '\\'; if (!lpszRoot && *lpszNext == ':' && *(lpszNext + 1) == '\\') lpszRoot = lpszNext + 1; } /* NAMEMAX + 2, must include C: TE*/ for (lpszLast = lpszNext = lpszPathNamep, nChars = 0; *lpszNext != '\0' && nChars < NAMEMAX+2;) { /* 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 check for '.' and '..' and move down */ /* as appropriate. */ else if (*(lpszNext + 1) == '.') { if (*(lpszNext + 2) == '.' && !(*(lpszNext + 3))) { /* At the end, just truncate */ /* and exit. */ if (lpszLast == lpszRoot) *(lpszLast + 1) = '\0'; else *lpszLast = '\0'; return; } 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); flDotDot = TRUE; } /* If we're at the end of a string, */ /* just exit. */ else if (*(lpszNext + 2) == NULL) { return; } /* Added this "else" because otherwise we might not pass any of the foregoing tests, as in the case where the incoming string refers to a suffix only, like ".bat" -SRM */ else { lpszLast = lpszNext++; } } 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; } }