1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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, sflags;
47	SFMTXDECL(f);
48
49	/* get the control flags */
50	if((sflags = _sftype(mode,&oflags,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 && (oflags &= (O_TEXT|O_BINARY|O_APPEND)) != 0 )
78		{	/* set file access control */
79			int ctl = sysfcntlf(f->file, F_GETFL, 0);
80			ctl = (ctl & ~(O_TEXT|O_BINARY|O_APPEND)) | oflags;
81			sysfcntlf(f->file, F_SETFL, ctl);
82		}
83
84		SFMTXRETURN(f,f);
85	}
86
87	if(sflags&SF_STRING)
88	{	f = sfnew(f,(char*)file,
89		  	  file ? (size_t)strlen((char*)file) : (size_t)SF_UNBOUND,
90		  	  -1,sflags);
91	}
92	else
93	{	if(!file)
94			return NIL(Sfio_t*);
95
96#if _has_oflags /* open the file */
97		while((fd = sysopenf((char*)file,oflags,SF_CREATMODE)) < 0 && errno == EINTR)
98			errno = 0;
99#else
100		while((fd = sysopenf(file,oflags&O_ACCMODE)) < 0 && errno == EINTR)
101			errno = 0;
102		if(fd >= 0)
103		{	if((oflags&(O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
104			{	CLOSE(fd);	/* error: file already exists */
105				return NIL(Sfio_t*);
106			}
107			if(oflags&O_TRUNC )	/* truncate file */
108			{	reg int	tf;
109				while((tf = syscreatf(file,SF_CREATMODE)) < 0 &&
110				      errno == EINTR)
111					errno = 0;
112				CLOSE(tf);
113			}
114		}
115		else if(oflags&O_CREAT)
116		{	while((fd = syscreatf(file,SF_CREATMODE)) < 0 && errno == EINTR)
117				errno = 0;
118			if((oflags&O_ACCMODE) != O_WRONLY)
119			{	/* the file now exists, reopen it for read/write */
120				CLOSE(fd);
121				while((fd = sysopenf(file,oflags&O_ACCMODE)) < 0 &&
122				      errno == EINTR)
123					errno = 0;
124			}
125		}
126#endif
127		if(fd < 0)
128			return NIL(Sfio_t*);
129
130		/* we may have to reset the file descriptor to its old value */
131		oldfd = f ? f->file : -1;
132		if((f = sfnew(f,NIL(char*),(size_t)SF_UNBOUND,fd,sflags)) && oldfd >= 0)
133			(void)sfsetfd(f,oldfd);
134	}
135
136	return f;
137}
138
139#if __STD_C
140int _sftype(reg const char* mode, int* oflagsp, int* uflagp)
141#else
142int _sftype(mode, oflagsp, uflagp)
143reg char*	mode;
144int*		oflagsp;
145int*		uflagp;
146#endif
147{
148	reg int	sflags, oflags, uflag;
149
150	if(!mode)
151		return 0;
152
153	/* construct the open flags */
154	sflags = oflags = uflag = 0;
155	while(1) switch(*mode++)
156	{
157	case 'a' :
158		sflags |= SF_WRITE | SF_APPENDWR;
159		oflags |= O_WRONLY | O_APPEND | O_CREAT;
160		continue;
161	case 'b' :
162		oflags |= O_BINARY;
163		continue;
164	case 'm' :
165		sflags |= SF_MTSAFE;
166		uflag = 0;
167		continue;
168	case 'r' :
169		sflags |= SF_READ;
170		oflags |= O_RDONLY;
171		continue;
172	case 's' :
173		sflags |= SF_STRING;
174		continue;
175	case 't' :
176		oflags |= O_TEXT;
177		continue;
178	case 'u' :
179		sflags &= ~SF_MTSAFE;
180		uflag = 1;
181		continue;
182	case 'w' :
183		sflags |= SF_WRITE;
184		oflags |= O_WRONLY | O_CREAT;
185		if(!(sflags&SF_READ))
186			oflags |= O_TRUNC;
187		continue;
188	case 'x' :
189		oflags |= O_EXCL;
190		continue;
191	case 'F':
192		/* stdio compatibility -- fd >= FOPEN_MAX (or other magic number) ok */
193		continue;
194	case 'W' :
195		sflags |= SF_WCWIDTH;
196		uflag = 0;
197		continue;
198	case '+' :
199		if(sflags)
200			sflags |= SF_READ|SF_WRITE;
201		continue;
202	default :
203		if(!(oflags&O_CREAT) )
204			oflags &= ~O_EXCL;
205#if _WIN32 && !_WINIX
206		if(!(oflags&(O_BINARY|O_TEXT)))
207			oflags |= O_BINARY;
208#endif
209		if((sflags&SF_RDWR) == SF_RDWR)
210			oflags = (oflags&~O_ACCMODE)|O_RDWR;
211		if(oflagsp)
212			*oflagsp = oflags;
213		if(uflagp)
214			*uflagp = uflag;
215		if((sflags&(SF_STRING|SF_RDWR)) == SF_STRING)
216			sflags |= SF_READ;
217		return sflags;
218	}
219}
220