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

  1. /***
  2. *tmpfile.c - create unique file name or file
  3. *
  4. *       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines tmpnam() and tmpfile().
  8. *
  9. *******************************************************************************/
  10.  
  11.  
  12. #ifdef _WIN32
  13.  
  14.  
  15. #include <cruntime.h>
  16. #include <errno.h>
  17. #include <process.h>
  18. #include <fcntl.h>
  19. #include <io.h>
  20. #include <mtdll.h>
  21. #include <share.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <file2.h>
  28. #include <internal.h>
  29. #include <tchar.h>
  30. #include <dbgint.h>
  31.  
  32. /*
  33.  * Buffers used by tmpnam() and tmpfile() to build filenames.
  34.  */
  35. static _TSCHAR namebuf0[L_tmpnam] = { 0 };      /* used by tmpnam()  */
  36. static _TSCHAR namebuf1[L_tmpnam] = { 0 };      /* used by tmpfile() */
  37.  
  38. /*
  39.  * Initializing function for namebuf0 and namebuf1.
  40.  */
  41. #ifdef _UNICODE
  42. static void __cdecl winit_namebuf(int);
  43. #else  /* _UNICODE */
  44. static void __cdecl init_namebuf(int);
  45. #endif  /* _UNICODE */
  46.  
  47. /*
  48.  * Generator function that produces temporary filenames
  49.  */
  50. #ifdef _UNICODE
  51. static int __cdecl wgenfname(wchar_t *);
  52. #else  /* _UNICODE */
  53. static int __cdecl genfname(char *);
  54. #endif  /* _UNICODE */
  55.  
  56.  
  57. /***
  58. *_TSCHAR *tmpnam(_TSCHAR *s) - generate temp file name
  59. *
  60. *Purpose:
  61. *       Creates a file name that is unique in the directory specified by
  62. *       _P_tmpdir in stdio.h.  Places file name in string passed by user or
  63. *       in static mem if pass NULL.
  64. *
  65. *Entry:
  66. *       _TSCHAR *s - ptr to place to put temp name
  67. *
  68. *Exit:
  69. *       returns pointer to constructed file name (s or address of static mem)
  70. *       returns NULL if fails
  71. *
  72. *Exceptions:
  73. *
  74. *******************************************************************************/
  75.  
  76. _TSCHAR * __cdecl _ttmpnam (
  77.         _TSCHAR *s
  78.         )
  79. {
  80. #ifdef _MT
  81.         _ptiddata ptd;
  82. #endif  /* _MT */
  83.         _mlock(_TMPNAM_LOCK);
  84.  
  85.         /*
  86.          * Initialize namebuf0, if needed. Otherwise, call genfname() to
  87.          * generate the next filename.
  88.          */
  89.         if ( *namebuf0 == 0 ) {
  90. #ifdef _UNICODE
  91.                 winit_namebuf(0);
  92. #else  /* _UNICODE */
  93.                 init_namebuf(0);
  94. #endif  /* _UNICODE */
  95.         }
  96. #ifdef _UNICODE
  97.         else if ( wgenfname(namebuf0) )
  98. #else  /* _UNICODE */
  99.         else if ( genfname(namebuf0) )
  100. #endif  /* _UNICODE */
  101.                 goto tmpnam_err;
  102.  
  103.         /*
  104.          * Generate a filename that doesn't already exist.
  105.          */
  106.         while ( _taccess(namebuf0, 0) == 0 )
  107. #ifdef _UNICODE
  108.                 if ( wgenfname(namebuf0) )
  109. #else  /* _UNICODE */
  110.                 if ( genfname(namebuf0) )
  111. #endif  /* _UNICODE */
  112.                         goto tmpnam_err;
  113.  
  114.         /*
  115.          * Filename has successfully been generated.
  116.          */
  117.         if ( s == NULL )
  118. #ifdef _MT
  119.         {
  120.                 /*
  121.                  * Use a per-thread buffer to hold the generated file name.
  122.                  * If there isn't one, and one cannot be created, just use
  123.                  * namebuf0.
  124.                  */
  125.                 ptd = _getptd();
  126. #ifdef _UNICODE
  127.                 if ( (ptd->_wnamebuf0 != NULL) || ((ptd->_wnamebuf0 =
  128.                       _malloc_crt(L_tmpnam * sizeof(wchar_t))) != NULL) )
  129.                 {
  130.                         s = ptd->_wnamebuf0;
  131.                         wcscpy(s, namebuf0);
  132.                 }
  133. #else  /* _UNICODE */
  134.                 if ( (ptd->_namebuf0 != NULL) || ((ptd->_namebuf0 =
  135.                       _malloc_crt(L_tmpnam)) != NULL) )
  136.                 {
  137.                         s = ptd->_namebuf0;
  138.                         strcpy(s, namebuf0);
  139.                 }
  140. #endif  /* _UNICODE */
  141.                 else
  142.                         s = namebuf0;
  143.         }
  144. #else  /* _MT */
  145.                 s = namebuf0;
  146. #endif  /* _MT */
  147.         else
  148.                 _tcscpy(s, namebuf0);
  149.  
  150.         _munlock(_TMPNAM_LOCK);
  151.         return s;
  152.  
  153.         /*
  154.          * Error return path. All errors exit through here.
  155.          */
  156. tmpnam_err:
  157.         _munlock(_TMPNAM_LOCK);
  158.         return NULL;
  159. }
  160.  
  161. #ifndef _UNICODE
  162.  
  163. /***
  164. *FILE *tmpfile() - create a temporary file
  165. *
  166. *Purpose:
  167. *       Creates a temporary file with the file mode "w+b".  The file
  168. *       will be automatically deleted when closed or the program terminates
  169. *       normally.
  170. *
  171. *Entry:
  172. *       None.
  173. *
  174. *Exit:
  175. *       Returns stream pointer to opened file.
  176. *       Returns NULL if fails
  177. *
  178. *Exceptions:
  179. *
  180. *******************************************************************************/
  181.  
  182. FILE * __cdecl tmpfile (
  183.         void
  184.         )
  185. {
  186.         FILE *stream;
  187.         int fh;
  188.  
  189.         _mlock(_TMPNAM_LOCK);
  190.  
  191.         /*
  192.          * Initialize namebuf1, if needed. Otherwise, call genfname() to
  193.          * generate the next filename.
  194.          */
  195.         if ( *namebuf1 == 0 ) {
  196.                 init_namebuf(1);
  197.         }
  198.         else if ( genfname(namebuf1) )
  199.                 goto tmpfile_err0;
  200.  
  201.         /*
  202.          * Get a free stream.
  203.          *
  204.          * Note: In multi-thread models, the stream obtained below is locked!
  205.          */
  206.         if ( (stream = _getstream()) == NULL )
  207.                 goto tmpfile_err0;
  208.  
  209.         /*
  210.          * Create a temporary file.
  211.          *
  212.          * Note: The loop below will only create a new file. It will NOT
  213.          * open and truncate an existing file. Either behavior is probably
  214.          * legal under ANSI (4.9.4.3 says tmpfile "creates" the file, but
  215.          * also says it is opened with mode "wb+"). However, the behavior
  216.          * implemented below is compatible with prior versions of MS-C and
  217.          * makes error checking easier.
  218.          */
  219.         while ( ((fh = _sopen(namebuf1,
  220.                               _O_CREAT | _O_EXCL | _O_RDWR | _O_BINARY |
  221.                                 _O_TEMPORARY,
  222.                               _SH_DENYNO,
  223.                               _S_IREAD | _S_IWRITE
  224.                              ))
  225.             == -1) && (errno == EEXIST) )
  226.                 if ( genfname(namebuf1) )
  227.                         break;
  228.  
  229.         /*
  230.          * Check that the loop above did indeed create a temporary
  231.          * file.
  232.          */
  233.         if ( fh == -1 )
  234.                 goto tmpfile_err1;
  235.  
  236.         /*
  237.          * Initialize stream
  238.          */
  239. #ifdef _DEBUG
  240.         if ( (stream->_tmpfname = _malloc_crt( (_tcslen( namebuf1 ) + 1) *
  241.                sizeof(_TSCHAR) )) == NULL )
  242. #else  /* _DEBUG */
  243.         if ( (stream->_tmpfname = _tcsdup( namebuf1 )) == NULL )
  244. #endif  /* _DEBUG */
  245.         {
  246.                 /* close the file, then branch to error handling */
  247.                 _close(fh);
  248.                 goto tmpfile_err1;
  249.         }
  250. #ifdef _DEBUG
  251.         _tcscpy( stream->_tmpfname, namebuf1 );
  252. #endif  /* _DEBUG */
  253.         stream->_cnt = 0;
  254.         stream->_base = stream->_ptr = NULL;
  255.         stream->_flag = _commode | _IORW;
  256.         stream->_file = fh;
  257.  
  258.         _unlock_str(stream);
  259.         _munlock(_TMPNAM_LOCK);
  260.         return stream;
  261.  
  262.         /*
  263.          * Error return. All errors paths branch to one of the two
  264.          * labels below.
  265.          */
  266. tmpfile_err1:
  267.         _unlock_str(stream);
  268. tmpfile_err0:
  269.         _munlock(_TMPNAM_LOCK);
  270.         return NULL;
  271. }
  272.  
  273. #endif  /* _UNICODE */
  274.  
  275. /***
  276. *static void init_namebuf(flag) - initializes the namebuf arrays
  277. *
  278. *Purpose:
  279. *       Called once each for namebuf0 and namebuf1, to initialize
  280. *       them.
  281. *
  282. *Entry:
  283. *       int flag            - flag set to 0 if namebuf0 is to be initialized,
  284. *                             non-zero (1) if namebuf1 is to be initialized.
  285. *Exit:
  286. *
  287. *Exceptions:
  288. *
  289. *******************************************************************************/
  290.  
  291. #ifdef _UNICODE
  292. static void __cdecl winit_namebuf(
  293. #else  /* _UNICODE */
  294. static void __cdecl init_namebuf(
  295. #endif  /* _UNICODE */
  296.         int flag
  297.         )
  298. {
  299.         _TSCHAR *p, *q;
  300.  
  301.         if ( flag == 0 )
  302.             p = namebuf0;
  303.         else
  304.             p = namebuf1;
  305.  
  306.         /*
  307.          * Put in the path prefix. Make sure it ends with a slash or
  308.          * backslash character.
  309.          */
  310. #ifdef _UNICODE
  311.         wcscpy(p, _wP_tmpdir);
  312. #else  /* _UNICODE */
  313.         strcpy(p, _P_tmpdir);
  314. #endif  /* _UNICODE */
  315.         q = p + sizeof(_P_tmpdir) - 1;      /* same as p + _tcslen(p) */
  316.  
  317.         if  ( (*(q - 1) != _T('\\')) && (*(q - 1) != _T('/')) )
  318.                 *(q++) = _T('\\');
  319.  
  320.         /*
  321.          * Append the leading character of the filename.
  322.          */
  323.         if ( flag )
  324.                 /* for tmpfile() */
  325.                 *(q++) = _T('t');
  326.         else
  327.                 /* for tmpnam() */
  328.                 *(q++) = _T('s');
  329.  
  330.         /*
  331.          * Append the process id, encoded in base 32. Note this makes
  332.          * p back into a string again (i.e., terminated by a '\0').
  333.          */
  334.         _ultot((unsigned long)_getpid(), q, 32);
  335.         _tcscat(p, _T("."));
  336. }
  337.  
  338.  
  339. /***
  340. *static int genfname(_TSCHAR *fname) -
  341. *
  342. *Purpose:
  343. *
  344. *Entry:
  345. *
  346. *Exit:
  347. *
  348. *Exceptions:
  349. *
  350. *******************************************************************************/
  351.  
  352. #ifdef _UNICODE
  353. static int __cdecl wgenfname (
  354. #else  /* _UNICODE */
  355. static int __cdecl genfname (
  356. #endif  /* _UNICODE */
  357.         _TSCHAR *fname
  358.         )
  359. {
  360.         _TSCHAR *p;
  361.         _TSCHAR pext[4];
  362.         unsigned long extnum;
  363.  
  364.         p = _tcsrchr(fname, _T('.'));
  365.  
  366.         p++;
  367.  
  368.         if ( (extnum = _tcstoul(p, NULL, 32) + 1) >= (unsigned long)TMP_MAX )
  369.                 return -1;
  370.  
  371.         _tcscpy(p, _ultot(extnum, pext, 32));
  372.  
  373.         return 0;
  374. }
  375.  
  376. #if !defined (_UNICODE) && !defined (CRTDLL)
  377.  
  378. /***
  379. *void __inc_tmpoff(void) - force external reference for _tmpoff
  380. *
  381. *Purpose:
  382. *       Forces an external reference to be generate for _tmpoff, which is
  383. *       is defined in cinittmp.obj. This has the forces cinittmp.obj to be
  384. *       pulled in, making a call to rmtmp part of the termination.
  385. *
  386. *Entry:
  387. *
  388. *Exit:
  389. *
  390. *Exceptions:
  391. *
  392. *******************************************************************************/
  393.  
  394.  
  395. extern int _tmpoff;
  396.  
  397. void __inc_tmpoff(
  398.         void
  399.         )
  400. {
  401.         _tmpoff++;
  402. }
  403.  
  404. #endif  /* !defined (_UNICODE) && !defined (CRTDLL) */
  405.  
  406.  
  407. #else  /* _WIN32 */
  408.  
  409. #if defined (_M_MPPC) || defined (_M_M68K)
  410.  
  411.  
  412. #include <cruntime.h>
  413. #include <stdio.h>
  414. #include <share.h>
  415. #include <stdlib.h>
  416. #include <file2.h>
  417. #include <io.h>
  418. #include <malloc.h>
  419. #include <errno.h>
  420. #include <internal.h>
  421. #include <string.h>
  422. #include <dbgint.h>
  423. #include <macos\osutils.h>
  424. #include <macos\files.h>
  425. #include <macos\errors.h>
  426. #include <macos\gestalte.h>
  427. #include <macos\traps.h>
  428. #include <macos\toolutil.h>
  429. #include <macos\folders.h>
  430.  
  431. static char namebuf[L_tmpnam];  /* internal static buffer for tmpnam */
  432.  
  433.  
  434. /***
  435. *char *tmpnam(s) - generate temp file name
  436. *
  437. *Purpose:
  438. *       Creates a file name that is unique in the directory specified by
  439. *       _P_tmpdir in stdio.h.  Places file name in string passed by user or
  440. *       in static mem if pass NULL.
  441. *
  442. *Entry:
  443. *       char *s - ptr to place to put temp name
  444. *
  445. *Exit:
  446. *       returns pointer to constructed file name (s or address of static mem)
  447. *       returns NULL if fails
  448. *
  449. *Exceptions:
  450. *
  451. *******************************************************************************/
  452.  
  453. char * __cdecl tmpnam (
  454.         REG1 char *s
  455.         )
  456. {
  457.         int olderrno;
  458.         unsigned int first;
  459.         OSErr osErr;
  460.         short foundVRefNum;
  461.         long foundDirID;
  462.         HParamBlockRec hparamBlock;
  463.         CInfoPBRec cinfoPB;
  464.         char *ptmp;
  465.         Str255 st, st2;
  466.         int fwrapped;
  467.  
  468.         /* use internal buffer if user didn't provide one */
  469.  
  470.         if (s == NULL)
  471.                 s = namebuf;
  472.  
  473.         /* construct base name */
  474.  
  475.         *s = '\0';
  476.  
  477.         /*decide if we are in system 7.0 or earlier version*/
  478.         /*if system 7.0, put in temp file folder, otherwise*/
  479.         /*put in system folder*/
  480.  
  481.         hparamBlock.volumeParam.ioNamePtr = &st2[0];
  482.         hparamBlock.volumeParam.ioVRefNum = 0;
  483.         hparamBlock.volumeParam.ioVolIndex = 1;
  484.         osErr = PBHGetVInfoSync(&hparamBlock);
  485.         if (osErr)
  486.                 {
  487.                 return NULL;
  488.                 }
  489.  
  490.         if (__TrapFromGestalt(gestaltFindFolderAttr, gestaltFindFolderPresent))
  491.                 {
  492.                 osErr = FindFolder((unsigned short)kOnSystemDisk, (OSType)kTemporaryFolderType, (Boolean)kCreateFolder,
  493.                         &foundVRefNum, &foundDirID);
  494.                 if (osErr)
  495.                         {
  496.                         return NULL;
  497.                         }
  498.                 }
  499.         else    /* put into system folder */
  500.                 {
  501.                 foundVRefNum = hparamBlock.volumeParam.ioVRefNum;
  502.                 foundDirID = hparamBlock.volumeParam.ioVFndrInfo[0];
  503.                 if (!foundDirID)
  504.                         {
  505.                         return NULL;
  506.                         }
  507.                 }
  508.  
  509.  
  510.         /* get full pathname -- folder name to put tmp file*/
  511.         cinfoPB.dirInfo.ioVRefNum = foundVRefNum;
  512.         cinfoPB.dirInfo.ioDrDirID = foundDirID;
  513.         cinfoPB.dirInfo.ioFDirIndex = -1; /*use ioDirID only*/
  514.         cinfoPB.dirInfo.ioNamePtr = &st[0];
  515.         osErr = PBGetCatInfoSync(&cinfoPB);
  516.         if (osErr)
  517.                 {
  518.                 return NULL;
  519.                 }
  520.         else
  521.                 {
  522.                 _p2cstr(st);            /* dir name system folder or temp items */
  523.                 _p2cstr(st2);           /* volume name */
  524.                 strcpy(s, st2);
  525.                 strcat(s, ":");
  526.                 strcat(s, st);
  527.                 }
  528.  
  529.         /* Loop until a non-existent filename is found */
  530.  
  531.         strcat(s, ":");
  532.         ptmp = s + strlen(s);
  533.  
  534.         olderrno = errno;
  535.         first = _tmpoff;
  536.  
  537.         fwrapped = 0;
  538.         do {
  539.             if (_tmpoff > TMP_MAX )
  540.                         {
  541.                         if (!fwrapped)
  542.                                 {
  543.                                 _tmpoff = 1;
  544.                                 fwrapped = 1;
  545.                                 }
  546.                         else
  547.                                 {
  548.                                 return (NULL);
  549.                                 }
  550.                         }
  551.                 _itoa( _tmpoff, ptmp, 10 );
  552.                 _tmpoff++;
  553.                 errno = 0;
  554.         }
  555.         while ( ( _access( s, 0 ) == 0 ) || ( errno == EACCES ) );
  556.  
  557.         errno = olderrno;
  558.  
  559.         return( s );
  560. }
  561.  
  562.  
  563. /***
  564. *FILE *tmpfile() - create a temporary file
  565. *
  566. *Purpose:
  567. *       Creates a temporary file with the file mode "w+b".  The file
  568. *       will be automatically deleted when closed or the program terminates
  569. *       normally.
  570. *
  571. *Entry:
  572. *       None.
  573. *
  574. *Exit:
  575. *       Returns stream pointer to opened file.
  576. *       Returns NULL if fails
  577. *
  578. *Exceptions:
  579. *
  580. *******************************************************************************/
  581.  
  582. FILE * __cdecl tmpfile (
  583.         void
  584.         )
  585. {
  586.         char name[ L_tmpnam ];
  587.         char *ptr;
  588.         FILE *stream;
  589.         int tmpnum;
  590.         FILE *retval;
  591.  
  592.         /* Call tmpnam() to generate the filename. Save the _tmpoff value. */
  593.  
  594.         ptr = name;
  595.         ptr = tmpnam( ptr );
  596.         tmpnum = _tmpoff - 1;
  597.  
  598.         /* Now get a free stream and open the file. */
  599.  
  600.         if ((stream = _getstream()) == NULL)
  601.                 return(NULL);
  602.  
  603.         retval = _openfile(name,"w+b",_SH_DENYNO,stream);
  604.  
  605.         if (retval != NULL)
  606. #ifdef _DEBUG
  607.                 if ( (stream->_tmpfname = _malloc_crt( strlen(ptr) + 1 ))
  608.                      != NULL )
  609.                         strcpy(stream->_tmpfname, ptr);
  610. #else  /* _DEBUG */
  611.                 stream->_tmpfname = _strdup(ptr);   /* store _tmpoff value */
  612. #endif  /* _DEBUG */
  613.  
  614.         return(retval);
  615. }
  616.  
  617.  
  618. #endif  /* defined (_M_MPPC) || defined (_M_M68K) */
  619.  
  620. #endif  /* _WIN32 */
  621.