1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#include	"sfhdr.h"
23
24/*	Open a file/string for IO.
25**	If f is not nil, it is taken as an existing stream that should be
26**	closed and its structure reused for the new stream.
27**
28**	Written by Kiem-Phong Vo.
29*/
30
31#if _BLD_sfio && defined(__EXPORT__)
32#define extern  __EXPORT__
33#endif
34extern
35#undef  extern
36
37#if __STD_C
38Sfio_t* _sfopen(Sfio_t* f, const char* file, const char* mode)
39#else
40Sfio_t* _sfopen(f,file,mode)
41Sfio_t*		f;		/* old stream structure */
42char*		file;		/* file/string to be opened */
43char*		mode;		/* mode of the stream */
44#endif
45{
46	int	fd, oldfd, oflags, fflags, sflags;
47	SFMTXDECL(f);
48
49	/* get the control flags */
50	if((sflags = _sftype(mode,&oflags,&fflags,NIL(int*))) == 0)
51		return NIL(Sfio_t*);
52
53	/* changing the control flags */
54	if(f && !file && !((f->flags|sflags)&SF_STRING) )
55	{	SFMTXENTER(f, NIL(Sfio_t*));
56
57		if(f->mode&SF_INIT ) /* stream uninitialized, ok to set flags */
58		{	f->flags |= (sflags & (SF_FLAGS & ~SF_RDWR));
59
60			if((sflags &= SF_RDWR) != 0) /* reset read/write modes */
61			{	f->flags = (f->flags & ~SF_RDWR) | sflags;
62
63				if((f->flags&SF_RDWR) == SF_RDWR)
64					f->bits |= SF_BOTH;
65				else	f->bits &= ~SF_BOTH;
66
67				if(f->flags&SF_READ)
68					f->mode = (f->mode&~SF_WRITE)|SF_READ;
69				else	f->mode = (f->mode&~SF_READ)|SF_WRITE;
70			}
71		}
72		else /* make sure there is no buffered data */
73		{	if(sfsync(f) < 0)
74				SFMTXRETURN(f,NIL(Sfio_t*));
75		}
76
77		if(f->file >= 0 )
78		{	if ((oflags &= (O_TEXT|O_BINARY|O_APPEND)) != 0 )
79			{	/* set file access control */
80				int ctl = sysfcntlf(f->file, F_GETFL, 0);
81				ctl = (ctl & ~(O_TEXT|O_BINARY|O_APPEND)) | oflags;
82				sysfcntlf(f->file, F_SETFL, ctl);
83			}
84#if !O_cloexec
85			if (fflags & SF_FD_CLOEXEC)
86				SETCLOEXEC(f->file);
87#endif
88		}
89
90		SFMTXRETURN(f,f);
91	}
92
93	if(sflags&SF_STRING)
94	{	f = sfnew(f,(char*)file,
95		  	  file ? (size_t)strlen((char*)file) : (size_t)SF_UNBOUND,
96		  	  -1,sflags);
97	}
98	else
99	{	if(!file)
100			return NIL(Sfio_t*);
101
102#if _has_oflags /* open the file */
103		while((fd = sysopenf((char*)file,oflags,SF_CREATMODE)) < 0 && errno == EINTR)
104			errno = 0;
105#else
106		while((fd = sysopenf(file,oflags&O_ACCMODE)) < 0 && errno == EINTR)
107			errno = 0;
108		if(fd >= 0)
109		{	if((oflags&(O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
110			{	CLOSE(fd);	/* error: file already exists */
111				return NIL(Sfio_t*);
112			}
113			if(oflags&O_TRUNC )	/* truncate file */
114			{	reg int	tf;
115				while((tf = syscreatf(file,SF_CREATMODE)) < 0 &&
116				      errno == EINTR)
117					errno = 0;
118				CLOSE(tf);
119			}
120		}
121		else if(oflags&O_CREAT)
122		{	while((fd = syscreatf(file,SF_CREATMODE)) < 0 && errno == EINTR)
123				errno = 0;
124			if((oflags&O_ACCMODE) != O_WRONLY)
125			{	/* the file now exists, reopen it for read/write */
126				CLOSE(fd);
127				while((fd = sysopenf(file,oflags&O_ACCMODE)) < 0 &&
128				      errno == EINTR)
129					errno = 0;
130			}
131		}
132#endif
133		if(fd < 0)
134			return NIL(Sfio_t*);
135
136		/* we may have to reset the file descriptor to its old value */
137		oldfd = f ? f->file : -1;
138		if((f = sfnew(f,NIL(char*),(size_t)SF_UNBOUND,fd,sflags)) && oldfd >= 0)
139			(void)sfsetfd(f,oldfd);
140	}
141
142	return f;
143}
144
145#if __STD_C
146int _sftype(reg const char* mode, int* oflagsp, int* fflagsp, int* uflagp)
147#else
148int _sftype(mode, oflagsp, fflagsp, uflagp)
149reg char*	mode;
150int*		oflagsp;
151int*		fflagsp;
152int*		uflagp;
153#endif
154{
155	reg int	sflags, oflags, fflags, uflag;
156
157	if(!mode)
158		return 0;
159
160	/* construct the open flags */
161	sflags = oflags = fflags = uflag = 0;
162	while(1) switch(*mode++)
163	{
164	case 'a' :
165		sflags |= SF_WRITE | SF_APPENDWR;
166		oflags |= O_WRONLY | O_APPEND | O_CREAT;
167		continue;
168	case 'b' :
169		oflags |= O_BINARY;
170		continue;
171	case 'e' :
172		oflags |= O_cloexec;
173		fflags |= SF_FD_CLOEXEC;
174		continue;
175	case 'm' :
176		sflags |= SF_MTSAFE;
177		uflag = 0;
178		continue;
179	case 'r' :
180		sflags |= SF_READ;
181		oflags |= O_RDONLY;
182		continue;
183	case 's' :
184		sflags |= SF_STRING;
185		continue;
186	case 't' :
187		oflags |= O_TEXT;
188		continue;
189	case 'u' :
190		sflags &= ~SF_MTSAFE;
191		uflag = 1;
192		continue;
193	case 'w' :
194		sflags |= SF_WRITE;
195		oflags |= O_WRONLY | O_CREAT;
196		if(!(sflags&SF_READ))
197			oflags |= O_TRUNC;
198		continue;
199	case 'x' :
200		oflags |= O_EXCL;
201		continue;
202	case 'F':
203		/* stdio compatibility -- fd >= FOPEN_MAX (or other magic number) ok */
204		continue;
205	case 'W' :
206		sflags |= SF_WCWIDTH;
207		uflag = 0;
208		continue;
209	case '+' :
210		if(sflags)
211			sflags |= SF_READ|SF_WRITE;
212		continue;
213	default :
214		if(!(oflags&O_CREAT) )
215			oflags &= ~O_EXCL;
216#if _WIN32 && !_WINIX
217		if(!(oflags&(O_BINARY|O_TEXT)))
218			oflags |= O_BINARY;
219#endif
220		if((sflags&SF_RDWR) == SF_RDWR)
221			oflags = (oflags&~O_ACCMODE)|O_RDWR;
222		if(oflagsp)
223			*oflagsp = oflags;
224		if(fflagsp)
225			*fflagsp = fflags;
226		if(uflagp)
227			*uflagp = uflag;
228		if((sflags&(SF_STRING|SF_RDWR)) == SF_STRING)
229			sflags |= SF_READ;
230		return sflags;
231	}
232}
233