bc9fab4183b42f9b73f2136af778588ac5aa00d4
[fw/pdclib] / functions / stdio / fopen.c
1 /* $Id$ */
2
3 /* fopen( const char *, const char * )
4
5    This file is part of the Public Domain C Library (PDCLib).
6    Permission is granted to use, modify, and / or redistribute at will.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11
12 #ifndef REGTEST
13 #include <_PDCLIB_glue.h>
14 #include <string.h>
15
16 extern struct _PDCLIB_file_t * _PDCLIB_filelist;
17
18 struct _PDCLIB_file_t * fopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode )
19 {
20     struct _PDCLIB_file_t * rc;
21     size_t filename_len;
22     if ( mode == NULL || filename == NULL || filename[0] == '\0' )
23     {
24         /* Mode or filename invalid */
25         return NULL;
26     }
27     /* To reduce the number of malloc calls, all data fields are concatenated:
28        * the FILE structure itself,
29        * ungetc buffer,
30        * filename buffer,
31        * data buffer.
32        Data buffer comes last because it might change in size ( setvbuf() ).
33     */
34     filename_len = strlen( filename ) + 1;
35     if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + filename_len + BUFSIZ ) ) == NULL )
36     {
37         /* no memory */
38         return NULL;
39     }
40     if ( ( rc->status = _PDCLIB_filemode( mode ) ) == 0 ) 
41     {
42         /* invalid mode */
43         free( rc );
44         return NULL;
45     }
46     rc->handle = _PDCLIB_open( filename, rc->status );
47     if ( rc->handle == _PDCLIB_NOHANDLE )
48     {
49         /* OS open() failed */
50         free( rc );
51         return NULL;
52     }
53     /* Setting pointers into the memory block allocated above */
54     rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t );
55     rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE;
56     rc->buffer   = rc->filename + filename_len;
57     /* Copying filename to FILE structure */
58     strcpy( rc->filename, filename );
59     /* Initializing the rest of the structure */
60     rc->bufsize = BUFSIZ;
61     rc->bufidx = 0;
62     rc->ungetidx = 0;
63     /* Setting buffer to _IOLBF because "when opened, a stream is fully
64        buffered if and only if it can be determined not to refer to an
65        interactive device."
66     */
67     rc->status |= _IOLBF;
68     /* TODO: Setting mbstate */
69     /* Adding to list of open files */
70     rc->next = _PDCLIB_filelist;
71     _PDCLIB_filelist = rc;
72     return rc;
73 }
74
75 #endif
76
77 #ifdef TEST
78 #include <_PDCLIB_test.h>
79
80 int main( void )
81 {
82     /* Some of the tests are not executed for regression tests, as the libc on
83        my system is at once less forgiving (segfaults on mode NULL) and more
84        forgiving (accepts undefined modes).
85     */
86     remove( "testing/testfile" );
87     TESTCASE_NOREG( fopen( NULL, NULL ) == NULL );
88     TESTCASE( fopen( NULL, "w" ) == NULL );
89     TESTCASE_NOREG( fopen( "", NULL ) == NULL );
90     TESTCASE( fopen( "", "w" ) == NULL );
91     TESTCASE( fopen( "foo", "" ) == NULL );
92     TESTCASE_NOREG( fopen( "testing/testfile", "wq" ) == NULL ); /* Undefined mode */
93     TESTCASE_NOREG( fopen( "testing/testfile", "wr" ) == NULL ); /* Undefined mode */
94     TESTCASE( fopen( "testing/testfile", "w" ) != NULL );
95     remove( "testing/testfile" );
96     return TEST_RESULTS;
97 }
98
99 #endif