summaryrefslogtreecommitdiffstats
path: root/private/crt32/stdio/tempnam.c
blob: 4539ba870c1b806ee6deb595b0fc94ecc33a7ed8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/***
*tempnam.c - generate unique file name
*
*	Copyright (c) 1986-1992, Microsoft Corporation. All rights reserved.
*
*Purpose:
*
*Revision History:
*	??-??-??  TC	initial version
*	04-17-86  JMB	changed directory of last resort from \tmp to tmp.
*			eliminated use of L_tmpnam (it was incoorectly defined
*			in stdio.h and should not be used in tempnam; see
*			System V definition of tempnam.
*	04-23-86  TC	changed last try directory from tmp to current directory
*	04-29-86  JMB	bug fix: pfxlength was being set from strlen(pfx)
*			even if pfx was NULL.  Fixed to set pfxlength to zero
*			if pfx is NULL, strlen(pfx) otherwise.
*	05-28-86  TC	changed stat's to access's, and optimized code a bit
*	12-01-86  JMB	added support for Kanji file names until KANJI switch
*	12-15-86  JMB	free malloced memory if (++_tmpoff == first)
*	07-15-87  JCR	Re-init _tempoff based on length of pfx (fixes infinate
*			loop bug; also, tempnam() now uses _tempoff instead of
*			_tmpoff (used by tmpnam()).
*	10-16-87  JCR	Fixed bug in _tempoff re-init code if pfx is NULL.
*	11-09-87  JCR	Multi-thread version
*	12-11-87  JCR	Added "_LOAD_DS" to declaration
*	05-27-88  PHG	Merged DLL and normal versions
*	06-09-89  GJF	Propagated MT's change of 05-17-89 (Kanji)
*	02-16-90  GJF	Fixed copyright and indents
*	03-19-90  GJF	Replaced _LOAD_DS and _CALLTYPE1 and added #include
*			<cruntime.h>.
*	03-26-90  GJF	Added #include <io.h>.
*	08-13-90  SBM	Compiles cleanly with -W3, replaced explicit register
*			declarations by REGn references
*	10-03-90  GJF	New-style function declarator.
*	01-21-91  GJF	ANSI naming.
*	08-19-91  JCR	Allow quotes in TMP variable path
*	08-27-91  JCR	ANSI naming
*	08-25-92  GJF	Don't build for POSIX.
*	11-30-92  KRS	Generalize KANJI support to MBCS. Port 16-bit bug fix.
*
*******************************************************************************/

#ifndef _POSIX_

#include <cruntime.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <malloc.h>
#include <string.h>
#include <internal.h>
#include <os2dll.h>

#ifdef _MBCS
#include <mbstring.h>
#endif

static char * _stripquote (char *);

/***
*char *_tempnam(dir, prefix) - create unique file name
*
*Purpose:
*	Create a file name that is unique in the specified directory.
*	The semantics of directory specification is as follows:
*	Use the directory specified by the TMP environment variable
*	if that exists, else use the dir argument if non-NULL, else
*	use _P_tmpdir if that directory exists, else use the current
*	working directory), else return NULL.
*
*Entry:
*	char *dir - directory to be used for temp file if TMP env var
*		    not set
*	char *prefix - user provided prefix for temp file name
*
*Exit:
*	returns ptr to constructed file name if successful
*	returns NULL if unsuccessful
*
*Exceptions:
*
*******************************************************************************/

char * _CALLTYPE1 _tempnam (
	char *dir,
	char *pfx
	)
{
	REG1 char *ptr;
	REG2 unsigned int pfxlength=0;
	char *s;
	char *pfin;
	unsigned int first;
	char * qptr = NULL;	/* ptr to TMP path with quotes stripped out */

	/* try TMP path */
	if ( ( ptr = getenv( "TMP" ) ) && ( _access( ptr, 0 ) != -1 ) )
		dir = ptr;

	/* try stripping quotes out of TMP path */
	else if ( (ptr != NULL) && (qptr = _stripquote(ptr)) &&
		  (_access(qptr, 0) != -1 ) )
		dir = qptr;

	/* TMP path not available, use alternatives */
	else if (!( dir != NULL && ( _access( dir, 0 ) != -1 ) ) )
	/* do not "simplify" this depends on side effects!! */
	{
		free(qptr);	/* free buffer, if non-NULL */
		if ( _access( _P_tmpdir, 0 ) != -1 )
		    dir = _P_tmpdir;
		else
		    dir = ".";
	}


	if (pfx)
		pfxlength = strlen(pfx);
	if ( ( s = malloc(strlen(dir) + pfxlength + 8 ) ) == NULL )
		/* the 8 above allows for a backslash, 6 char temp string and
		   a null terminator */
	{
		goto done2;
	}
	*s = '\0';
	strcat( s, dir );
	pfin = &(dir[ strlen( dir ) - 1 ]);
#ifdef _MBCS
	if (*pfin == '\\') {
		if (pfin != _mbsrchr(dir,'\\'))
			/* *pfin is second byte of a double-byte char */
			strcat( s, "\\" );
	}
	else if (*pfin != '/')
		strcat( s, "\\" );
#else
	if ( ( *pfin != '\\' ) && ( *pfin != '/' ) )
	{
		strcat( s, "\\" );
	}
#endif
	if ( pfx != NULL )
	{
		strcat( s, pfx );
	}
	ptr = &s[strlen( s )];

	/*
	Re-initialize _tempoff if necessary.  If we don't re-init _tempoff, we
	can get into an infinate loop (e.g., (a) _tempoff is a big number on
	entry, (b) prefix is a long string (e.g., 8 chars) and all tempfiles
	with that prefix exist, (c) _tempoff will never equal first and we'll
	loop forever).

	[NOTE: To avoid a conflict that causes the same bug as that discussed
	above, _tempnam() uses _tempoff; tmpnam() uses _tmpoff]
	*/

	_mlock(_TMPNAM_LOCK);	/* Lock access to _old_pfxlen and _tempoff */

	if (_old_pfxlen < pfxlength)
		_tempoff = 1;
	_old_pfxlen = pfxlength;

	first = _tempoff;

	do {
		if ( ++_tempoff == first ) {
			free(s);
			s = NULL;
			goto done1;
		}
		_itoa( _tempoff, ptr, 10 );
		if ( strlen( ptr ) + pfxlength > 8 )
		{
			*ptr = '\0';
			_tempoff = 0;
		}
	}
	while ( (_access( s, 0 ) == 0 ) || (errno == EACCES) );


    /* Common return */
done1:
	_munlock(_TMPNAM_LOCK);     /* release tempnam lock */
done2:
	free(qptr);		    /* free temp ptr, if non-NULL */
	return(s);
}



/***
*_stripquote() - Strip quotes out of a string
*
*Purpose:
*	This routine strips quotes out of a string.  This is necessary
*	in the case where a file/path name has embedded quotes (i.e.,
*	new file system.)
*
*	For example,
*			c:\tmp\"a b c"\d --> c:\tmp\a b d\d
*
*	NOTE:  This routine makes a copy of the string since it may be
*	passed a pointer to an environment variable that shouldn't be
*	changed.  It is up to the caller to free up the memory (if the
*	return value is non-NULL).
*
*Entry:
*	char * ptr = pointer to string
*
*Exit:
*	char * ptr = pointer to copy of string with quotes gone.
*	NULL = no quotes in string.
*
*Exceptions:
*
*******************************************************************************/

char * _stripquote (src)
char * src;
{
    char * dst;
    char * ret;
    unsigned int q = 0;


    /* get a buffer for the new string */

    if ((dst = malloc(strlen(src)+1)) == NULL)
	return(NULL);

    /* copy the string stripping out the quotes */

    ret = dst;		/* save base ptr */

    while (*src) {

	if (*src == '\"') {
	    src++; q++;
	    }
	else
	    *dst++ =  *src++;
	}

    if (q) {
	*dst = '\0';	/* final nul */
	return(ret);
	}
    else {
	free(ret);
	return(NULL);
	}

}


#endif	/* _POSIX_ */