]> pd.if.org Git - pdclib/blob - functions/stdio/fopen.c
Added setvbuf().
[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
15 /* FIXME: This approach is a possible attack vector. */
16 struct _PDCLIB_file_t * _PDCLIB_filelist = NULL;
17
18 /* Helper function that parses the C-style mode string passed to fopen() into
19    the PDCLib flags FREAD, FWRITE, FAPPEND, FRW (read-write) and FBIN (binary
20    mode).
21 */
22 static unsigned int filemode( char const * const mode )
23 {
24     int rc = 0;
25     switch ( mode[0] )
26     {
27         case 'r':
28             rc |= _PDCLIB_FREAD;
29             break;
30         case 'w':
31             rc |= _PDCLIB_FWRITE;
32             break;
33         case 'a':
34             rc |= _PDCLIB_FAPPEND;
35             break;
36         default:
37             /* Other than read, write, or append - invalid */
38             return 0;
39     }
40     for ( size_t i = 1; i < 4; ++i )
41     {
42         switch ( mode[i] )
43         {
44             case '+':
45                 if ( rc & _PDCLIB_FRW ) return 0; /* Duplicates are invalid */
46                 rc |= _PDCLIB_FRW;
47                 break;
48             case 'b':
49                 if ( rc & _PDCLIB_FBIN ) return 0; /* Duplicates are invalid */
50                 rc |= _PDCLIB_FBIN;
51                 break;
52             case '\0':
53                 /* End of mode */
54                 return rc;
55             default:
56                 /* Other than read/write or binary - invalid. */
57                 return 0;
58         }
59     }
60     /* Longer than three chars - invalid. */
61     return 0;
62 }
63
64 struct _PDCLIB_file_t * fopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode )
65 {
66     struct _PDCLIB_file_t * rc;
67     if ( mode == NULL || filename == NULL || filename[0] == '\0' )
68     {
69         /* Mode or filename invalid */
70         return NULL;
71     }
72     if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) ) ) == NULL )
73     {
74         /* no memory for another FILE */
75         return NULL;
76     }
77     if ( ( rc->status = filemode( mode ) ) == 0 ) goto fail; /* invalid mode */
78     rc->handle = _PDCLIB_open( filename, rc->status );
79     if ( rc->handle == _PDCLIB_NOHANDLE ) goto fail; /* OS open() failed */
80     /* Adding to list of open files */
81     rc->next = _PDCLIB_filelist;
82     _PDCLIB_filelist = rc;
83     /* Setting buffer, and mark as internal. TODO: Check for unbuffered? */
84     if ( ( rc->buffer = malloc( BUFSIZ ) ) == NULL ) goto fail;
85     rc->status |= ( _PDCLIB_LIBBUFFER | _PDCLIB_VIRGINSTR );
86     /* TODO: Setting mbstate */
87     return rc;
88 fail:
89     free( rc );
90     return NULL;
91 }
92
93 #endif
94
95 #ifdef TEST
96 #include <_PDCLIB_test.h>
97
98 int main( void )
99 {
100 #ifndef REGTEST
101     TESTCASE( filemode( "r" ) == _PDCLIB_FREAD );
102     TESTCASE( filemode( "w" ) == _PDCLIB_FWRITE );
103     TESTCASE( filemode( "a" ) == _PDCLIB_FAPPEND );
104     TESTCASE( filemode( "r+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW ) );
105     TESTCASE( filemode( "w+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW ) );
106     TESTCASE( filemode( "a+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FRW ) );
107     TESTCASE( filemode( "rb" ) == ( _PDCLIB_FREAD | _PDCLIB_FBIN ) );
108     TESTCASE( filemode( "wb" ) == ( _PDCLIB_FWRITE | _PDCLIB_FBIN ) );
109     TESTCASE( filemode( "ab" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FBIN ) );
110     TESTCASE( filemode( "r+b" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) );
111     TESTCASE( filemode( "w+b" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) );
112     TESTCASE( filemode( "a+b" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FRW | _PDCLIB_FBIN ) );
113     TESTCASE( filemode( "rb+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) );
114     TESTCASE( filemode( "wb+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) );
115     TESTCASE( filemode( "ab+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FRW | _PDCLIB_FBIN ) );
116     TESTCASE( fopen( NULL, NULL ) == NULL );
117     TESTCASE( fopen( NULL, "w" ) == NULL );
118     TESTCASE( fopen( "", NULL ) == NULL );
119     TESTCASE( fopen( "", "w" ) == NULL );
120     TESTCASE( fopen( "foo", "" ) == NULL );
121     TESTCASE( fopen( "testfile", "wq" ) == NULL ); /* Illegal mode */
122     TESTCASE( fopen( "testfile", "wr" ) == NULL ); /* Illegal mode */
123     TESTCASE( fopen( "testfile", "w" ) != NULL );
124     system( "rm testfile" );
125 #else
126     puts( " NOTEST fopen() test driver is PDCLib-specific." );
127 #endif
128     return TEST_RESULTS;
129 }
130
131 #endif