# All header files of the project
HDRFILES := $(shell find $(PROJDIRS) -mindepth 1 -maxdepth 3 -name "*.h")
# All .c files in functions/_PDCLIB that do not have a regression test driver
-INTFILES := _Exit atomax digits open print scan remove rename seed stdinit strtox_main strtox_prelim filemode eol errno seek prepread prepwrite allocpages
+INTFILES := _Exit atomax digits open print scan remove rename seed stdinit strtox_main strtox_prelim filemode eol errno seek prepread prepwrite allocpages tmpfilename
# All object files in the library
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
# All test drivers (.t)
return EOF;
}
}
- /* Free buffer */
- if ( stream->status & _PDCLIB_LIBBUFFER )
- {
- free( stream->buffer );
- }
/* Close handle */
_PDCLIB_close( stream->handle );
/* Remove stream from list */
#ifndef REGTEST
#include <_PDCLIB_glue.h>
+#include <string.h>
extern struct _PDCLIB_file_t * _PDCLIB_filelist;
struct _PDCLIB_file_t * fopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode )
{
struct _PDCLIB_file_t * rc;
+ size_t filename_len;
if ( mode == NULL || filename == NULL || filename[0] == '\0' )
{
/* Mode or filename invalid */
return NULL;
}
- if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) ) ) == NULL )
+ /* To reduce the number of malloc calls, all data fields are concatenated:
+ * the FILE structure itself,
+ * ungetc buffer,
+ * filename buffer,
+ * data buffer.
+ Data buffer comes last because it might change in size ( setvbuf() ).
+ */
+ filename_len = strlen( filename ) + 1;
+ if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + filename_len + BUFSIZ ) ) == NULL )
{
- /* no memory for another FILE */
+ /* no memory */
return NULL;
}
if ( ( rc->status = _PDCLIB_filemode( mode ) ) == 0 )
free( rc );
return NULL;
}
- /* Adding to list of open files */
- rc->next = _PDCLIB_filelist;
- _PDCLIB_filelist = rc;
- /* Setting buffer, and mark as internal. TODO: Check for unbuffered */
- if ( ( rc->buffer = malloc( BUFSIZ ) ) == NULL )
- {
- free( rc );
- return NULL;
- }
- if ( ( rc->ungetbuf = malloc( _PDCLIB_UNGETCBUFSIZE ) ) == NULL )
- {
- free( rc->buffer );
- free( rc );
- return NULL;
- }
+ /* Setting pointers into the memory block allocated above */
+ rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t );
+ rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE;
+ rc->buffer = rc->filename + filename_len;
+ /* Copying filename to FILE structure */
+ strcpy( rc->filename, filename );
+ /* Initializing the rest of the structure */
rc->bufsize = BUFSIZ;
rc->bufidx = 0;
rc->ungetidx = 0;
*/
rc->status |= _PDCLIB_LIBBUFFER | _IOLBF;
/* TODO: Setting mbstate */
+ /* Adding to list of open files */
+ rc->next = _PDCLIB_filelist;
+ _PDCLIB_filelist = rc;
return rc;
}
typedef struct _PDCLIB_imaxdiv_t imaxdiv_t;
+#define SCNu32 "u"
+#define PRNu32 "u"
/* TODO: Print / Scan Macros */
/*
PRId8 PRIdLEAST8 PRIdFAST8 PRIdMAX
#define _PDCLIB_EOFFLAG 2048u
#define _PDCLIB_WIDESTREAM 4096u
#define _PDCLIB_BYTESTREAM 8192u
+#define _PDCLIB_DELONCLOSE 16384u
/* Position / status structure for getpos() / fsetpos(). */
struct _PDCLIB_fpos_t
#ifndef REGTEST
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <_PDCLIB_glue.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+/* This is an example implementation of tmpfile() fit for use with POSIX
+ POSIX kernels.
+*/
struct _PDCLIB_file_t * tmpfile( void )
{
- /* TODO: Implement */
- return NULL;
+ FILE * rc;
+ /* This is the chosen way to get high-quality randomness. Replace as
+ appropriate.
+ */
+ FILE * randomsource = fopen( "/dev/urandom", "rb" );
+ char filename[ L_tmpnam ];
+ _PDCLIB_fd_t fd;
+ if ( randomsource == NULL )
+ {
+ return NULL;
+ }
+ for ( ;; )
+ {
+ /* Get a filename candidate. What constitutes a valid filename and
+ where temporary files are usually located is platform-dependent,
+ which is one reason why this function is located in the platform
+ overlay. The other reason is that a *good* implementation should
+ use high-quality randomness instead of a pseudo-random sequence to
+ generate the filename candidate, which is *also* platform-dependent.
+ */
+ uint32_t random;
+ fscanf( randomsource, "%" SCNu32, &random );
+ sprintf( filename, "/tmp/%010" PRNu32 ".tmp", random );
+ /* Check if file of this name exists. Note that fopen() is a very weak
+ check, which does not take e.g. access permissions into account
+ (file might exist but not readable). Replace with something more
+ appropriate.
+ */
+ fd = open( filename, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR );
+ if ( fd != -1 )
+ {
+ break;
+ }
+ close( fd );
+ }
+ fclose( randomsource );
+ /* See fopen(). */
+ if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + L_tmpnam + BUFSIZ ) ) == NULL )
+ {
+ /* No memory to set up FILE structure */
+ close( fd );
+ return NULL;
+ }
+ rc->status = _PDCLIB_filemode( "wb+" ) | _PDCLIB_LIBBUFFER | _IOLBF | _PDCLIB_DELONCLOSE;
+ rc->handle = fd;
+ rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t );
+ rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE;
+ rc->buffer = rc->filename + L_tmpnam;
+ strcpy( rc->filename, filename );
+ rc->bufsize = BUFSIZ;
+ rc->bufidx = 0;
+ rc->ungetidx = 0;
+ rc->next = _PDCLIB_filelist;
+ _PDCLIB_filelist = rc;
+ return rc;
}
#endif
}
#endif
+
*/
#include <stdio.h>
-#include <stdarg.h>
#ifndef REGTEST
+#include <string.h>
+#include <_PDCLIB_glue.h>
+
char * tmpnam( char * s )
{
- /* TODO: Implement. */
- return NULL;
+ static char filename[ L_tmpnam ];
+ FILE * file = tmpfile();
+ if ( s == NULL )
+ {
+ s = filename;
+ }
+ strcpy( s, file->filename );
+ fclose( file );
+ return s;
}
#endif
#ifdef TEST
#include <_PDCLIB_test.h>
+#include <string.h>
+
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ TESTCASE( strlen( tmpnam( NULL ) ) < L_tmpnam );
return TEST_RESULTS;
}
#endif
+