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

  1. /***
  2. *tempnam.c - generate unique file name
  3. *
  4. *       Copyright (c) 1986-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *******************************************************************************/
  9.  
  10. #ifndef _MAC
  11.  
  12.  
  13.  
  14. #include <cruntime.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <io.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <errno.h>
  21. #include <malloc.h>
  22. #include <string.h>
  23. #include <internal.h>
  24. #include <mtdll.h>
  25. #include <tchar.h>
  26. #include <dbgint.h>
  27.  
  28. #ifdef _MBCS
  29. #include <mbstring.h>
  30. #endif  /* _MBCS */
  31.  
  32. /* local tchar */
  33. #ifdef _UNICODE
  34. #define _tP_tmpdir _wP_tmpdir
  35. #else  /* _UNICODE */
  36. #define _tP_tmpdir _P_tmpdir
  37. #endif  /* _UNICODE */
  38.  
  39. #ifdef _UNICODE
  40. static wchar_t * _wstripquote (wchar_t *);
  41. #else  /* _UNICODE */
  42. static char * _stripquote (char *);
  43. #endif  /* _UNICODE */
  44.  
  45. /***
  46. *_TSCHAR *_tempnam(dir, prefix) - create unique file name
  47. *
  48. *Purpose:
  49. *       Create a file name that is unique in the specified directory.
  50. *       The semantics of directory specification is as follows:
  51. *       Use the directory specified by the TMP environment variable
  52. *       if that exists, else use the dir argument if non-NULL, else
  53. *       use _P_tmpdir if that directory exists, else use the current
  54. *       working directory), else return NULL.
  55. *
  56. *Entry:
  57. *       _TSCHAR *dir - directory to be used for temp file if TMP env var
  58. *                   not set
  59. *       _TSCHAR *prefix - user provided prefix for temp file name
  60. *
  61. *Exit:
  62. *       returns ptr to constructed file name if successful
  63. *       returns NULL if unsuccessful
  64. *
  65. *Exceptions:
  66. *
  67. *******************************************************************************/
  68.  
  69. _TSCHAR * __cdecl _ttempnam (
  70.         const _TSCHAR *dir,
  71.         const _TSCHAR *pfx
  72.         )
  73. {
  74.         REG1 _TSCHAR *ptr;
  75.         REG2 unsigned int pfxlength = 0;
  76.         _TSCHAR *s;
  77.         _TSCHAR *pfin;
  78.         unsigned int first;
  79.         unsigned int bufsz;
  80.         _TSCHAR * qptr = NULL;  /* ptr to TMP path with quotes stripped out */
  81.  
  82.         /* try TMP path */
  83.         if ( ( ptr = _tgetenv( _T("TMP") ) ) && ( _taccess( ptr, 0 ) != -1 ) )
  84.                 dir = ptr;
  85.  
  86.         /* try stripping quotes out of TMP path */
  87. #ifdef _UNICODE
  88.         else if ( (ptr != NULL) && (qptr = _wstripquote(ptr)) &&
  89. #else  /* _UNICODE */
  90.         else if ( (ptr != NULL) && (qptr = _stripquote(ptr)) &&
  91. #endif  /* _UNICODE */
  92.                   (_taccess(qptr, 0) != -1 ) )
  93.                 dir = qptr;
  94.  
  95.         /* TMP path not available, use alternatives */
  96.         else if (!( dir != NULL && ( _taccess( dir, 0 ) != -1 ) ) )
  97.         /* do not "simplify" this depends on side effects!! */
  98.         {
  99.                 _free_crt(qptr);        /* free buffer, if non-NULL */
  100.                 if ( _taccess( _tP_tmpdir, 0 ) != -1 )
  101.                     dir = _tP_tmpdir;
  102.                 else
  103.                     dir = _T(".");
  104.         }
  105.  
  106.  
  107.         if (pfx)
  108.                 pfxlength = _tcslen(pfx);
  109.  
  110.         if ( ((bufsz = _tcslen(dir) + pfxlength + 12) > FILENAME_MAX) ||
  111.              ((s = malloc(bufsz * sizeof(_TSCHAR))) == NULL) )
  112.                 /* the 12 above allows for a backslash, 10 char temp string and
  113.                    a null terminator */
  114.         {
  115.                 goto done2;
  116.         }
  117.  
  118.         *s = _T('\0');
  119.         _tcscat( s, dir );
  120.         pfin = (_TSCHAR *)&(dir[ _tcslen( dir ) - 1 ]);
  121.  
  122. #ifdef _MBCS
  123.         if (*pfin == '\\') {
  124.                 if (pfin != _mbsrchr(dir,'\\'))
  125.                         /* *pfin is second byte of a double-byte char */
  126.                         strcat( s, "\\" );
  127.         }
  128.         else if (*pfin != '/')
  129.                 strcat( s, "\\" );
  130. #else  /* _MBCS */
  131.         if ( ( *pfin != _T('\\') ) && ( *pfin != _T('/') ) )
  132.         {
  133.                 _tcscat( s, _T("\\") );
  134.         }
  135. #endif  /* _MBCS */
  136.  
  137.         if ( pfx != NULL )
  138.         {
  139.                 _tcscat( s, pfx );
  140.         }
  141.         ptr = &s[_tcslen( s )];
  142.  
  143.         /*
  144.         Re-initialize _tempoff if necessary.  If we don't re-init _tempoff, we
  145.         can get into an infinate loop (e.g., (a) _tempoff is a big number on
  146.         entry, (b) prefix is a long string (e.g., 8 chars) and all tempfiles
  147.         with that prefix exist, (c) _tempoff will never equal first and we'll
  148.         loop forever).
  149.  
  150.         [NOTE: To avoid a conflict that causes the same bug as that discussed
  151.         above, _tempnam() uses _tempoff; tmpnam() uses _tmpoff]
  152.         */
  153.  
  154.         _mlock(_TMPNAM_LOCK);   /* Lock access to _old_pfxlen and _tempoff */
  155.  
  156.         if (_old_pfxlen < pfxlength)
  157.                 _tempoff = 1;
  158.         _old_pfxlen = pfxlength;
  159.  
  160.         first = _tempoff;
  161.  
  162.         do {
  163.                 if ( (++_tempoff - first) > TMP_MAX ) {
  164.                         free(s);
  165.                         s = NULL;
  166.                         goto done1;
  167.                 }
  168.                 /* the maximum length string returned by _ultot is 10 chars
  169.                    (assuming 32-bit unsigned long) so there is enough room in
  170.                    the tail of s (pointed to by ptr) for it */
  171.                 _ultot( (unsigned long)_tempoff, ptr, 10 );
  172.         }
  173.         while ( (_taccess( s, 0 ) == 0 ) || (errno == EACCES) );
  174.  
  175.  
  176.         /* Common return */
  177. done1:
  178.         _munlock(_TMPNAM_LOCK);     /* release tempnam lock */
  179. done2:
  180.         _free_crt(qptr);            /* free temp ptr, if non-NULL */
  181.         return(s);
  182. }
  183.  
  184.  
  185.  
  186. /***
  187. *_stripquote() - Strip quotes out of a string
  188. *
  189. *Purpose:
  190. *       This routine strips quotes out of a string.  This is necessary
  191. *       in the case where a file/path name has embedded quotes (i.e.,
  192. *       new file system.)
  193. *
  194. *       For example,
  195. *                       c:\tmp\"a b c"\d --> c:\tmp\a b d\d
  196. *
  197. *       NOTE:  This routine makes a copy of the string since it may be
  198. *       passed a pointer to an environment variable that shouldn't be
  199. *       changed.  It is up to the caller to free up the memory (if the
  200. *       return value is non-NULL).
  201. *
  202. *Entry:
  203. *       _TSCHAR * ptr = pointer to string
  204. *
  205. *Exit:
  206. *       _TSCHAR * ptr = pointer to copy of string with quotes gone.
  207. *       NULL = no quotes in string.
  208. *
  209. *Exceptions:
  210. *
  211. *******************************************************************************/
  212.  
  213. #ifdef _UNICODE
  214. static wchar_t * _wstripquote (
  215. #else  /* _UNICODE */
  216. static char * _stripquote (
  217. #endif  /* _UNICODE */
  218.         _TSCHAR * src
  219.         )
  220. {
  221.         _TSCHAR * dst;
  222.         _TSCHAR * ret;
  223.         unsigned int q = 0;
  224.  
  225.  
  226.         /* get a buffer for the new string */
  227.  
  228.         if ((dst = _malloc_crt((_tcslen(src)+1) * sizeof(_TSCHAR))) == NULL)
  229.                 return(NULL);
  230.  
  231.         /* copy the string stripping out the quotes */
  232.  
  233.         ret = dst;          /* save base ptr */
  234.  
  235.         while (*src) {
  236.  
  237.                 if (*src == _T('\"')) {
  238.                         src++; q++;
  239.                 }
  240.                 else
  241.                         *dst++ =  *src++;
  242.         }
  243.  
  244.         if (q) {
  245.                 *dst = _T('\0');        /* final nul */
  246.                 return(ret);
  247.         }
  248.         else {
  249.                 _free_crt(ret);
  250.                 return(NULL);
  251.         }
  252.  
  253. }
  254.  
  255.  
  256.  
  257. #else  /* _MAC */
  258.  
  259.  
  260. #include <cruntime.h>
  261. #include <sys/types.h>
  262. #include <sys/stat.h>
  263. #include <io.h>
  264. #include <stdio.h>
  265. #include <stdlib.h>
  266. #include <errno.h>
  267. #include <malloc.h>
  268. #include <string.h>
  269. #include <tchar.h>
  270. #include <internal.h>
  271. #include <macos\osutils.h>
  272. #include <macos\files.h>
  273. #include <macos\errors.h>
  274. #include <macos\gestalte.h>
  275. #include <macos\traps.h>
  276. #include <macos\toolutil.h>
  277. #include <macos\folders.h>
  278.  
  279. #ifdef _MBCS
  280. #include <mbctype.h>
  281. #include <mbstring.h>
  282. #define STRSTR  _mbsstr
  283. #else  /* _MBCS */
  284. #define STRSTR  strstr
  285. #endif  /* _MBCS */
  286.  
  287. /***
  288. *char *_tempnam(dir, prefix) - create unique file name
  289. *
  290. *Purpose:
  291. *       Create a file name that is unique in the specified directory.
  292. *       The semantics of directory specification is as follows:
  293. *       Use the directory specified by the TMP environment variable
  294. *       if that exists, else use the dir argument if non-NULL, else
  295. *       use Temporary File Folder in System 7.x or System Folder in System
  296. *  6.x, if that directory exists, else use the current
  297. *       working directory), else return NULL.
  298. *
  299. *Entry:
  300. *       char *dir - directory to be used for temp file if TMP env var
  301. *                   not set
  302. *       char *prefix - user provided prefix for temp file name
  303. *
  304. *Exit:
  305. *       returns ptr to constructed file name if successful
  306. *       returns NULL if unsuccessful
  307. *
  308. *Exceptions:
  309. *
  310. *******************************************************************************/
  311.  
  312. char * __cdecl _tempnam (
  313.         const char *dir,
  314.         const char *pfx
  315.         )
  316. {
  317.         REG1 char *ptr;
  318.         REG2 unsigned int pfxlength=0;
  319.         char *s;
  320.         unsigned int first;
  321.         OSErr osErr;
  322.         short foundVRefNum;
  323.         long foundDirID;
  324.         HParamBlockRec hparamBlock;
  325.         CInfoPBRec cinfoPB;
  326.         Str255 st, st2;
  327. #ifdef _MBCS
  328.         _TSCHAR *pfin;
  329. #endif  /* _MBCS */
  330.  
  331.         if ((s = (char *)malloc(256*sizeof(char))) == NULL)
  332.         {
  333.                 return NULL;
  334.         }
  335.         memset(s, '\0', 256);
  336.         if (!( dir != NULL && ( _access( dir, 0 ) != -1 ) ) )
  337.         /* do not "simplify" this depends on side effects!! */
  338.         {
  339.                 hparamBlock.volumeParam.ioNamePtr = &st2[0];
  340.                 hparamBlock.volumeParam.ioVRefNum = 0;
  341.                 hparamBlock.volumeParam.ioVolIndex = 1;
  342.                 osErr = PBHGetVInfoSync(&hparamBlock);
  343.                 if (osErr)
  344.                 {
  345.                         s[0] = '\0';
  346.                         goto CurrentDir;
  347.                 }
  348.                 /* get temporary file folder or system folder*/
  349.  
  350.                 if (__TrapFromGestalt( gestaltFindFolderAttr,
  351.                                        gestaltFindFolderPresent ))
  352.                 {
  353.                         osErr = FindFolder( (unsigned short)kOnSystemDisk,
  354.                                             kTemporaryFolderType,
  355.                                             kCreateFolder,
  356.                                             &foundVRefNum,
  357.                                             &foundDirID );
  358.                         if (osErr)
  359.                         {
  360.                                 s[0] = '\0';
  361.                                 goto CurrentDir;
  362.                         }
  363.                 }
  364.                 else    /*put into system folder*/
  365.                 {
  366.                         foundVRefNum = hparamBlock.volumeParam.ioVRefNum;
  367.                         foundDirID = hparamBlock.volumeParam.ioVFndrInfo[0];
  368.                         if (!foundDirID)
  369.                         {
  370.                                 s[0] = '\0';
  371.                                 goto CurrentDir;
  372.                         }
  373.                 }
  374.  
  375.  
  376.                 /* get full pathname -- folder name to put tmp file*/
  377.                 cinfoPB.dirInfo.ioVRefNum = foundVRefNum;
  378.                 cinfoPB.dirInfo.ioDrDirID = foundDirID;
  379.                 cinfoPB.dirInfo.ioFDirIndex = -1; /*use ioDirID only*/
  380.                 cinfoPB.dirInfo.ioNamePtr = &st[0];
  381.                 osErr = PBGetCatInfoSync(&cinfoPB);
  382.                 if (osErr)
  383.                 {
  384.                         s[0] = '\0';
  385.                         goto CurrentDir;
  386.                 }
  387.                 else
  388.                 {
  389.                         _p2cstr(st);        /* dir name */
  390.                         _p2cstr(st2);       /* volume name */
  391.                         strcpy(s, st2);
  392.                         strcat(s, ":");
  393.                         strcat(s, st);
  394.                         strcat(s, ":");
  395.                 }
  396.         }
  397.         else    /* user supplied dir */
  398.         {
  399.                 if (STRSTR(dir, ":")== NULL)
  400.                 {
  401.                         /* if it is relative path with single name */
  402.                         strcpy(s, ":");
  403.                         strcat(s, dir);
  404.                 }
  405.                 else
  406.                 {
  407.                         strcpy(s, dir);
  408.                 }
  409. #ifndef _MBCS
  410.                 if (*(s+strlen(s)-1) != ':')
  411.                 {
  412.                         strcat(s, ":");
  413.                 }
  414. #else  /* _MBCS */
  415.                 pfin = (_TSCHAR *)&(dir[ strlen( dir ) - 1 ]);
  416.                 if (*pfin == ':') {
  417.                 if (pfin != _mbsrchr(s,':'))
  418.                         /* *pfin is second byte of a double-byte char */
  419.                         strcat( s, ":" );
  420.                 }
  421.                 else if (*pfin != ':')
  422.                         strcat( s, ":" );
  423. #endif  /* _MBCS */
  424.  
  425.         }
  426.  
  427.         /* Loop until a non-existent filename is found */
  428.  
  429. CurrentDir:
  430.  
  431.         if (pfx)
  432.                 pfxlength = strlen(pfx);
  433.  
  434.         if ((pfxlength + strlen(s)+1) > 255)  /* including ':' */
  435.                 return NULL;
  436.  
  437.         if ( pfx != NULL )
  438.         {
  439.                 strcat( s, pfx );
  440.         }
  441.         ptr = &s[strlen( s )];
  442.  
  443.         /*
  444.         Re-initialize _tempoff if necessary.  If we don't re-init _tempoff, we
  445.         can get into an infinate loop (e.g., (a) _tempoff is a big number on
  446.         entry, (b) prefix is a long string (e.g., 8 chars) and all tempfiles
  447.         with that prefix exist, (c) _tempoff will never equal first and we'll
  448.         loop forever).
  449.  
  450.         [NOTE: To avoid a conflict that causes the same bug as that discussed
  451.         above, _tempnam() uses _tempoff; tmpnam() uses _tmpoff]
  452.         */
  453.  
  454.         if (_old_pfxlen < pfxlength)
  455.                 _tempoff = 1;
  456.         _old_pfxlen = pfxlength;
  457.  
  458.         first = _tempoff;
  459.  
  460.         do {
  461.                 if ( _tempoff > TMP_MAX ) {
  462.                         free(s);
  463.                         s = NULL;
  464.                         goto done1;
  465.                 }
  466.                 _itoa( _tempoff, ptr, 10 );
  467.                 if ( strlen( ptr ) + pfxlength > 32 )
  468.                 {
  469.                         *ptr = '\0';
  470.                         _tempoff = TMP_MAX;
  471.                 }
  472.                 _tempoff++;
  473.         }
  474.         while ( (_access( s, 0 ) == 0 ) || (errno == EACCES) );
  475.  
  476.  
  477.     /* Common return */
  478. done1:
  479.         return(s);
  480. }
  481.  
  482.  
  483. #endif  /* _MAC */
  484.