home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / splitpat.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  6KB  |  187 lines

  1. /***
  2. *splitpath.c - break down path name into components
  3. *
  4. *       Copyright (c) 1987-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       To provide support for accessing the individual components of an
  8. *       arbitrary path name
  9. *
  10. *******************************************************************************/
  11.  
  12.  
  13. #include <cruntime.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #ifdef _MBCS
  17. #include <mbstring.h>
  18. #include <mbctype.h>
  19. #include <mbdata.h>
  20. #endif  /* _MBCS */
  21. #include <tchar.h>
  22.  
  23. /***
  24. *_splitpath() - split a path name into its individual components
  25. *
  26. *Purpose:
  27. *       to split a path name into its individual components
  28. *
  29. *Entry:
  30. *       path  - pointer to path name to be parsed
  31. *       drive - pointer to buffer for drive component, if any
  32. *       dir   - pointer to buffer for subdirectory component, if any
  33. *       fname - pointer to buffer for file base name component, if any
  34. *       ext   - pointer to buffer for file name extension component, if any
  35. *
  36. *Exit:
  37. *       drive - pointer to drive string.  Includes ':' if a drive was given.
  38. *       dir   - pointer to subdirectory string.  Includes leading and trailing
  39. *           '/' or '\', if any.
  40. *       fname - pointer to file base name
  41. *       ext   - pointer to file extension, if any.  Includes leading '.'.
  42. *
  43. *Exceptions:
  44. *
  45. *******************************************************************************/
  46.  
  47. void __cdecl _tsplitpath (
  48.         register const _TSCHAR *path,
  49.         _TSCHAR *drive,
  50.         _TSCHAR *dir,
  51.         _TSCHAR *fname,
  52.         _TSCHAR *ext
  53.         )
  54. {
  55.         register _TSCHAR *p;
  56.         _TSCHAR *last_slash = NULL, *dot = NULL;
  57.         unsigned len;
  58.  
  59.         /* we assume that the path argument has the following form, where any
  60.          * or all of the components may be missing.
  61.          *
  62.          *  <drive><dir><fname><ext>
  63.          *
  64.          * and each of the components has the following expected form(s)
  65.          *
  66.          *  drive:
  67.          *  0 to _MAX_DRIVE-1 characters, the last of which, if any, is a
  68.          *  ':'
  69.          *  dir:
  70.          *  0 to _MAX_DIR-1 characters in the form of an absolute path
  71.          *  (leading '/' or '\') or relative path, the last of which, if
  72.          *  any, must be a '/' or '\'.  E.g -
  73.          *  absolute path:
  74.          *      \top\next\last\     ; or
  75.          *      /top/next/last/
  76.          *  relative path:
  77.          *      top\next\last\  ; or
  78.          *      top/next/last/
  79.          *  Mixed use of '/' and '\' within a path is also tolerated
  80.          *  fname:
  81.          *  0 to _MAX_FNAME-1 characters not including the '.' character
  82.          *  ext:
  83.          *  0 to _MAX_EXT-1 characters where, if any, the first must be a
  84.          *  '.'
  85.          *
  86.          */
  87.  
  88.         /* extract drive letter and :, if any */
  89.  
  90.         if ((_tcslen(path) >= (_MAX_DRIVE - 2)) && (*(path + _MAX_DRIVE - 2) == _T(':'))) {
  91.             if (drive) {
  92.                 _tcsncpy(drive, path, _MAX_DRIVE - 1);
  93.                 *(drive + _MAX_DRIVE-1) = _T('\0');
  94.             }
  95.             path += _MAX_DRIVE - 1;
  96.         }
  97.         else if (drive) {
  98.             *drive = _T('\0');
  99.         }
  100.  
  101.         /* extract path string, if any.  Path now points to the first character
  102.          * of the path, if any, or the filename or extension, if no path was
  103.          * specified.  Scan ahead for the last occurence, if any, of a '/' or
  104.          * '\' path separator character.  If none is found, there is no path.
  105.          * We will also note the last '.' character found, if any, to aid in
  106.          * handling the extension.
  107.          */
  108.  
  109.         for (last_slash = NULL, p = (_TSCHAR *)path; *p; p++) {
  110. #ifdef _MBCS
  111.             if (_ISLEADBYTE (*p))
  112.                 p++;
  113.             else {
  114. #endif  /* _MBCS */
  115.             if (*p == _T('/') || *p == _T('\\'))
  116.                 /* point to one beyond for later copy */
  117.                 last_slash = p + 1;
  118.             else if (*p == _T('.'))
  119.                 dot = p;
  120. #ifdef _MBCS
  121.             }
  122. #endif  /* _MBCS */
  123.         }
  124.  
  125.         if (last_slash) {
  126.  
  127.             /* found a path - copy up through last_slash or max. characters
  128.              * allowed, whichever is smaller
  129.              */
  130.  
  131.             if (dir) {
  132.                 len = __min(((char *)last_slash - (char *)path) / sizeof(_TSCHAR),
  133.                     (_MAX_DIR - 1));
  134.                 _tcsncpy(dir, path, len);
  135.                 *(dir + len) = _T('\0');
  136.             }
  137.             path = last_slash;
  138.         }
  139.         else if (dir) {
  140.  
  141.             /* no path found */
  142.  
  143.             *dir = _T('\0');
  144.         }
  145.  
  146.         /* extract file name and extension, if any.  Path now points to the
  147.          * first character of the file name, if any, or the extension if no
  148.          * file name was given.  Dot points to the '.' beginning the extension,
  149.          * if any.
  150.          */
  151.  
  152.         if (dot && (dot >= path)) {
  153.             /* found the marker for an extension - copy the file name up to
  154.              * the '.'.
  155.              */
  156.             if (fname) {
  157.                 len = __min(((char *)dot - (char *)path) / sizeof(_TSCHAR),
  158.                     (_MAX_FNAME - 1));
  159.                 _tcsncpy(fname, path, len);
  160.                 *(fname + len) = _T('\0');
  161.             }
  162.             /* now we can get the extension - remember that p still points
  163.              * to the terminating nul character of path.
  164.              */
  165.             if (ext) {
  166.                 len = __min(((char *)p - (char *)dot) / sizeof(_TSCHAR),
  167.                     (_MAX_EXT - 1));
  168.                 _tcsncpy(ext, dot, len);
  169.                 *(ext + len) = _T('\0');
  170.             }
  171.         }
  172.         else {
  173.             /* found no extension, give empty extension and copy rest of
  174.              * string into fname.
  175.              */
  176.             if (fname) {
  177.                 len = __min(((char *)p - (char *)path) / sizeof(_TSCHAR),
  178.                     (_MAX_FNAME - 1));
  179.                 _tcsncpy(fname, path, len);
  180.                 *(fname + len) = _T('\0');
  181.             }
  182.             if (ext) {
  183.                 *ext = _T('\0');
  184.             }
  185.         }
  186. }
  187.