#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "file2.h"
#include "internal.h"

/***************************************************************************
 *
 * Function:    tempnam
 *
 * Description:
 *    Generate an unique file name. The name is not _guaranteed_ to be
 *    unique as UNIX is a multi-user system. (There is a possibility that
 *    some other process will also call tmpnam and get the same value back.
 *    To make the name unique, try to create the file and loop on the
 *    creation and tempnam calls until you are able to make the file. This
 *    approach is done by tmpfile.)
 * 
 * Entry:
 *    pszDirectory - Pointer to the directory for the file name. If none
 *                   is given, the environment variable "tmp" is used. If
 *                   "tmp" is undefined, then the define in stdio is used.
 *    pszPrefix    - Pointer to the template for the file name.
 *
 * Returns:
 *    A pointer to the file name or NULL to indicate a failure. The name
 *    is allocated from the heap with the help of "malloc".
 */

#ifdef ELF_LIBRARY
#define tempnam _tempnam
#endif

char *tempnam (const char *pszDirectory, const char *pszPrefix)
    {
    char          *pszAnswer = NULL;
    char          *pszTemp;
    const char    *pszDirName;
    size_t        sizePrefix = 0;
    unsigned long ulIndex;
/*
 *  Use the "tmp" directory from the envioronment variable. I will accept
 *  the entry in either case. I know that this is not standard, however,
 *  it is simpler to use the system. Of course, the first choice is the
 *  proper case for the name.
 */
    pszDirName = getenv ("tmp");
    if (pszDirName == NULL)
        {
	pszDirName = getenv ("TMP");
        }

    if (pszDirName != NULL)
        {
	if (access (pszDirName, 0) == -1)
	    {
	    pszDirName = NULL;
	    }
        }
/*
 *  If the director is not defined then use the input parameter
 */
    if (pszDirName == NULL)
        {
	pszDirName = pszDirectory;
	if (access (pszDirName, 0) == -1)
	    {
/*
 *   If the input parameter is not valid then use the "system defined"
 *   value.
 */
	    pszDirName = P_tmpdir;
	    if (access (pszDirName, 0) == -1)
	        {
/*
 *   If all else fails, use the current directory
 */
		pszDirName = ".";
	        }
	    }
        }
/*
 *  If there is a prefix then add update the length to include the prefix
 *  information.
 */
    if (pszPrefix != NULL)
        {
        sizePrefix = strlen (pszPrefix);
        }
    else
        {
	sizePrefix = 0;
        }
/*
 *  Allocate a buffer to hold the resulting file
 */
    pszAnswer = malloc (strlen (pszDirName) + sizePrefix + 8);
    if (pszAnswer != NULL)
        {
	strcpy (pszAnswer, pszDirName);
/*
 *  Ensure that the directory name is properly terminated
 */
	pszTemp = pszAnswer + strlen (pszAnswer);
	if (pszTemp[-1] != '/')
	    {
	    strcat (pszAnswer, "/");
	    }
/*
 *   Append the prefix name if so desired
 */
	if (pszPrefix != NULL)
	    {
	    strcat (pszAnswer, pszPrefix);
	    }
/*
 *    Generate numbers until a unique file name is obtained.
 */
	pszTemp = pszAnswer + strlen (pszAnswer);
	ulIndex = 0;

	for (;;)
	    {
	    ultoa (_tempoff + ulIndex, pszTemp, 10);
/*
 *  Try to access the file. If the file may be accessed then stop the
 *  operation.
 */
	    if (access (pszAnswer, 0) == 0)
	        {
		break;
	        }
/*
 *  If the file does not allow access then stop. An access denied is the
 *  only error which will cause us to cycle to the next number.
 */
	    if (errno != EACCES)
	        {
		break;
	        }
/*
 *  If we have tried too many times then give up. In this case, reject
 *  the operation.
 */
	    if (++ulIndex == 0)
	        {
		free (pszAnswer);
		pszAnswer = NULL;
		break;
	        }
	    }
/*
 *  This is the end of the operation. Update the last index found.
 */
	_tempoff += ulIndex + 1;
        }
/*
 *  This is the end. Return the pointer to the resulting string.
 */
    return (pszAnswer);
    }

#ifdef ELF_LIBRARY
__asm__(".weak tempnam; tempnam = _tempnam");
#endif
