PDCLIB-15: Make most stdio routines lock the stream and then call through to the _unlocked version
 #ifndef REGTEST\r
 #include <_PDCLIB_glue.h>\r
 #include <string.h>\r
+#include <threads.h>\r
 \r
 extern struct _PDCLIB_file_t * _PDCLIB_filelist;\r
 \r
 
 \r
 #ifndef REGTEST\r
 \r
-uint_fast64_t _PDCLIB_ftell64( struct _PDCLIB_file_t * stream )\r
+uint_fast64_t _PDCLIB_ftell64_unlocked( struct _PDCLIB_file_t * stream )\r
 {\r
     /* ftell() must take into account:\r
        - the actual *physical* offset of the file, i.e. the offset as recognized\r
     return ( stream->pos.offset - ( ( (int)stream->bufend - (int)stream->bufidx ) + (int)stream->ungetidx ) );\r
 }\r
 \r
+uint_fast64_t _PDCLIB_ftell64( struct _PDCLIB_file_t * stream )\r
+{\r
+  flockfile( stream );\r
+  uint_fast64_t pos = _PDCLIB_ftell64_unlocked( stream );\r
+  funlockfile( stream );\r
+  return pos;\r
+}\r
+\r
 #endif\r
 \r
 #ifdef TEST\r
 
 
 #ifndef REGTEST
 
-void clearerr( struct _PDCLIB_file_t * stream )
+void clearerr_unlocked( struct _PDCLIB_file_t * stream )
 {
     stream->status &= ~( _PDCLIB_ERRORFLAG | _PDCLIB_EOFFLAG );
 }
 
+void clearerr( struct _PDCLIB_file_t * stream )
+{
+    flockfile( stream );
+    clearerr_unlocked( stream );
+    funlockfile( stream );
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 #include <_PDCLIB_glue.h>
+#include <threads.h>
 
 extern struct _PDCLIB_file_t * _PDCLIB_filelist;
 
 
 
 #ifndef REGTEST
 
-int feof( struct _PDCLIB_file_t * stream )
+int feof_unlocked( struct _PDCLIB_file_t * stream )
 {
     return stream->status & _PDCLIB_EOFFLAG;
 }
 
+int feof( struct _PDCLIB_file_t * stream )
+{
+    flockfile( stream );
+    int eof = feof_unlocked( stream );
+    funlockfile( stream );
+    return eof;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
-int ferror( struct _PDCLIB_file_t * stream )
+int ferror_unlocked( struct _PDCLIB_file_t * stream )
 {
     return stream->status & _PDCLIB_ERRORFLAG;
 }
 
+int ferror( struct _PDCLIB_file_t * stream )
+{
+    flockfile( stream );
+    int error = ferror_unlocked( stream );
+    funlockfile( stream );
+    return error;
+}
+
 #endif
 
 #ifdef TEST
 
 
 extern struct _PDCLIB_file_t * _PDCLIB_filelist;
 
-int fflush( struct _PDCLIB_file_t * stream )
+int fflush_unlocked( struct _PDCLIB_file_t * stream )
 {
     if ( stream == NULL )
     {
         return _PDCLIB_flushbuffer( stream );
     }
 }
+
+int fflush( struct _PDCLIB_file_t * stream )
+{
+    flockfile( stream );
+    int res = fflush_unlocked(stream);
+    funlockfile( stream );
+    return res;
+}
                 
 #endif
 
 
 
 #include <_PDCLIB_glue.h>
 
-int fgetc( struct _PDCLIB_file_t * stream )
+int fgetc_unlocked( struct _PDCLIB_file_t * stream )
 {
     if ( _PDCLIB_prepread( stream ) == EOF )
     {
     return (unsigned char)stream->buffer[stream->bufidx++];
 }
 
+int fgetc( struct _PDCLIB_file_t * stream )
+{
+    flockfile( stream );
+    int c = fgetc_unlocked( stream );
+    funlockfile( stream );
+    return c;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
-int fgetpos( struct _PDCLIB_file_t * _PDCLIB_restrict stream, struct _PDCLIB_fpos_t * _PDCLIB_restrict pos )
+int fgetpos_unlocked( struct _PDCLIB_file_t * _PDCLIB_restrict stream, struct _PDCLIB_fpos_t * _PDCLIB_restrict pos )
 {
     pos->offset = stream->pos.offset + stream->bufidx - stream->ungetidx;
     pos->status = stream->pos.status;
     return 0;
 }
 
+int fgetpos( struct _PDCLIB_file_t * _PDCLIB_restrict stream, struct _PDCLIB_fpos_t * _PDCLIB_restrict pos )
+{
+    flockfile( stream );
+    int res = fgetpos_unlocked( stream, pos );
+    funlockfile( stream );
+    return res;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #include <_PDCLIB_glue.h>
 
-char * fgets( char * _PDCLIB_restrict s, int size, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+char * fgets_unlocked( char * _PDCLIB_restrict s, int size, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
 {
     if ( size == 0 )
     {
     return ( dest == s ) ? NULL : s;
 }
 
+char * fgets( char * _PDCLIB_restrict s, int size, 
+              struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+    flockfile( stream );
+    char* r = fgets_unlocked( s, size, stream );
+    funlockfile( stream );
+    return r;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
-int fprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... )
+int fprintf_unlocked( struct _PDCLIB_file_t * _PDCLIB_restrict stream, 
+                      const char * _PDCLIB_restrict format, ... )
 {
     int rc;
     va_list ap;
     return rc;
 }
 
+int fprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream,
+             const char * _PDCLIB_restrict format, ... )
+{
+    int rc;
+    va_list ap;
+    va_start( ap, format );
+    flockfile( stream );
+    rc = vfprintf_unlocked( stream, format, ap );
+    funlockfile( stream );
+    va_end( ap );
+    return rc;
+}
+
 #endif
 
 #ifdef TEST
 
    Returns c if successful, EOF otherwise.
    If a write error occurs, the error indicator of the stream is set.
 */
-int fputc( int c, struct _PDCLIB_file_t * stream )
+int fputc_unlocked( int c, struct _PDCLIB_file_t * stream )
 {
     if ( _PDCLIB_prepwrite( stream ) == EOF )
     {
     return c;
 }
 
+int fputc( int c, struct _PDCLIB_file_t * stream )
+{
+    flockfile( stream );
+    int r = fputc_unlocked( c, stream );
+    funlockfile( stream );
+    return r;
+}
+
 #endif
 
 #ifdef TEST
 
 #ifndef REGTEST
 #include <_PDCLIB_glue.h>
 
-int fputs( const char * _PDCLIB_restrict s, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+int fputs_unlocked( const char * _PDCLIB_restrict s, 
+                    struct _PDCLIB_file_t * _PDCLIB_restrict stream )
 {
     if ( _PDCLIB_prepwrite( stream ) == EOF )
     {
     return 0;
 }
 
+int fputs( const char * _PDCLIB_restrict s,
+           struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+    flockfile( stream );
+    int r = fputs_unlocked( s, stream );
+    funlockfile( stream );
+    return r;
+}
+
 #endif
 #ifdef TEST
 #include <_PDCLIB_test.h>
 
 #include <stdbool.h>
 #include <string.h>
 
-size_t fread( void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+size_t fread_unlocked( void * _PDCLIB_restrict ptr, 
+                       size_t size, size_t nmemb, 
+                       struct _PDCLIB_file_t * _PDCLIB_restrict stream )
 {
     if ( _PDCLIB_prepread( stream ) == EOF )
     {
     return nmemb_i;
 }
 
+size_t fread( void * _PDCLIB_restrict ptr, 
+              size_t size, size_t nmemb, 
+              struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+    flockfile( stream );
+    size_t r = fread_unlocked( ptr, size, nmemb, stream );
+    funlockfile( stream );
+    return r;
+}
+
 #endif
 
 #ifdef TEST
 
 #include <stdlib.h>
 #include <string.h>
 
-struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+struct _PDCLIB_file_t * freopen( 
+                            const char * _PDCLIB_restrict filename, 
+                            const char * _PDCLIB_restrict mode, 
+                            struct _PDCLIB_file_t * _PDCLIB_restrict stream )
 {
+    flockfile( stream );
+
     unsigned int status = stream->status & ( _IONBF | _IOLBF | _IOFBF | _PDCLIB_FREEBUFFER | _PDCLIB_DELONCLOSE );
     /* TODO: This function can change wide orientation of a stream */
     if ( stream->status & _PDCLIB_FWRITE )
     if ( ( filename == NULL ) && ( stream->filename == NULL ) )
     {
         /* TODO: Special handling for mode changes on std-streams */
+        funlockfile( stream );
         return NULL;
     }
     _PDCLIB_close( stream->handle );
         /* Allocate new buffer */
         if ( ( stream->filename = (char *)malloc( strlen( filename ) ) ) == NULL )
         {
+            funlockfile( stream );
             return NULL;
         }
         strcpy( stream->filename, filename );
     }
     if ( ( mode == NULL ) || ( filename[0] == '\0' ) )
     {
+        funlockfile( stream );
         return NULL;
     }
     if ( ( stream->status = _PDCLIB_filemode( mode ) ) == 0 )
     {
+        funlockfile( stream );
         return NULL;
     }
     /* Re-add the flags we saved above */
     /* TODO: Setting mbstate */
     if ( ( stream->handle = _PDCLIB_open( filename, stream->status ) ) == _PDCLIB_NOHANDLE )
     {
+        funlockfile( stream );
         return NULL;
     }
+    funlockfile( stream );
     return stream;
 }
 
 
 
 #ifndef REGTEST
 
-int fscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... )
+int fscanf_unlocked( FILE * _PDCLIB_restrict stream, 
+                     const char * _PDCLIB_restrict format, ... )
+{
+    int rc;
+    va_list ap;
+    va_start( ap, format );
+    rc = vfscanf_unlocked( stream, format, ap );
+    va_end( ap );
+    return rc;
+}
+
+int fscanf( FILE * _PDCLIB_restrict stream, 
+            const char * _PDCLIB_restrict format, ... )
 {
     int rc;
     va_list ap;
 
 
 #include <_PDCLIB_glue.h>
 
-int fseek( struct _PDCLIB_file_t * stream, long loffset, int whence )
+int fseek_unlocked( struct _PDCLIB_file_t * stream, long loffset, int whence )
 {
     _PDCLIB_int64_t offset = loffset;
     if ( stream->status & _PDCLIB_FWRITE )
     return ( _PDCLIB_seek( stream, offset, whence ) != EOF ) ? 0 : EOF;
 }
 
+int fseek( struct _PDCLIB_file_t * stream, long loffset, int whence )
+{
+    flockfile( stream );
+    int r = fseek_unlocked( stream, loffset, whence );
+    funlockfile( stream );
+    return r;
+}
+
 #endif
 
 #ifdef TEST
 
 #ifndef REGTEST
 #include <_PDCLIB_glue.h>
 
-int fsetpos( struct _PDCLIB_file_t * stream, const struct _PDCLIB_fpos_t * pos )
+int fsetpos_unlocked( struct _PDCLIB_file_t * stream, 
+                      const struct _PDCLIB_fpos_t * pos )
 {
     if ( stream->status & _PDCLIB_FWRITE )
     {
     return 0;
 }
 
+int fsetpos( struct _PDCLIB_file_t * stream, 
+             const struct _PDCLIB_fpos_t * pos )
+{
+    flockfile( stream );
+    int res = fsetpos_unlocked( stream, pos );
+    funlockfile( stream );
+    return res;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
-long int ftell( struct _PDCLIB_file_t * stream )
+long int ftell_unlocked( struct _PDCLIB_file_t * stream )
 {
-    uint_fast64_t off64 = _PDCLIB_ftell64( stream );
+    uint_fast64_t off64 = _PDCLIB_ftell64_unlocked( stream );
 
     if ( off64 > LONG_MAX )
     {
     return off64;
 }
 
+long int ftell( struct _PDCLIB_file_t * stream )
+{
+    flockfile( stream );
+    long int off = ftell_unlocked( stream );
+    funlockfile( stream );
+    return off;
+}
+
 #endif
 
 #ifdef TEST
 
 
 //TODO OS(2012-08-01): Ascertain purpose of lineend & potentially remove
 
-size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+size_t fwrite_unlocked( const void * _PDCLIB_restrict ptr, 
+               size_t size, size_t nmemb, 
+               struct _PDCLIB_file_t * _PDCLIB_restrict stream )
 {
     if ( _PDCLIB_prepwrite( stream ) == EOF )
     {
     return nmemb_i;
 }
 
+size_t fwrite( const void * _PDCLIB_restrict ptr, 
+               size_t size, size_t nmemb, 
+               struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+    flockfile( stream );
+    size_t r = fwrite_unlocked( ptr, size, nmemb, stream );
+    funlockfile( stream );
+    return r;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
+int getc_unlocked( struct _PDCLIB_file_t * stream )
+{
+    return fgetc_unlocked( stream );
+}
+
 int getc( struct _PDCLIB_file_t * stream )
 {
     return fgetc( stream );
 
 
 #ifndef REGTEST
 
+int getchar_unlocked( void )
+{
+    return fgetc_unlocked( stdin );
+}
+
+
 int getchar( void )
 {
     return fgetc( stdin );
 
     return rc;
 }
 
+int printf_unlocked( const char * _PDCLIB_restrict format, ... )
+{
+    int rc;
+    va_list ap;
+    va_start( ap, format );
+    rc = vfprintf_unlocked( stdout, format, ap );
+    va_end( ap );
+    return rc;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
+int putc_unlocked( int c, struct _PDCLIB_file_t * stream )
+{
+    return fputc_unlocked( c, stream );
+}
+
+
 int putc( int c, struct _PDCLIB_file_t * stream )
 {
     return fputc( c, stream );
 
 
 #ifndef REGTEST
 
+int putchar_unlocked( int c )
+{
+    return fputc_unlocked( c, stdout );
+}
+
 int putchar( int c )
 {
     return fputc( c, stdout );
 
 
 extern char * _PDCLIB_eol;
 
-int puts( const char * s )
+int puts_unlocked( const char * s )
 {
     if ( _PDCLIB_prepwrite( stdout ) == EOF )
     {
     }
 }
 
+int puts( const char * s )
+{
+    flockfile( stdout );
+    int r = puts_unlocked( s );
+    funlockfile( stdout );
+    return r;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
+int scanf_unlocked( const char * _PDCLIB_restrict format, ... )
+{
+    va_list ap;
+    va_start( ap, format );
+    return vfscanf_unlocked( stdin, format, ap );
+}
+
 int scanf( const char * _PDCLIB_restrict format, ... )
 {
     va_list ap;
 
 
 #ifndef REGTEST
 
-int ungetc( int c, struct _PDCLIB_file_t * stream )
+int ungetc_unlocked( int c, struct _PDCLIB_file_t * stream )
 {
     if ( c == EOF || stream->ungetidx == _PDCLIB_UNGETCBUFSIZE )
     {
     return stream->ungetbuf[stream->ungetidx++] = (unsigned char) c;
 }
 
+int ungetc( int c, struct _PDCLIB_file_t * stream )
+{
+    flockfile( stream );
+    int r = ungetc_unlocked( c, stream );
+    funlockfile( stream);
+    return r;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
-int vfprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg )
+int vfprintf_unlocked( struct _PDCLIB_file_t * _PDCLIB_restrict stream, 
+                       const char * _PDCLIB_restrict format, 
+                       va_list arg )
 {
     /* TODO: This function should interpret format as multibyte characters.  */
     struct _PDCLIB_status_t status;
     return status.i;
 }
 
+int vfprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, 
+              const char * _PDCLIB_restrict format, 
+              va_list arg )
+{
+    flockfile( stream );
+    int r = vfprintf_unlocked( stream, format, arg );
+    funlockfile( stream );
+    return r;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
-int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg )
+int vfscanf_unlocked( FILE * _PDCLIB_restrict stream, 
+                      const char * _PDCLIB_restrict format, 
+                      va_list arg )
 {
     /* TODO: This function should interpret format as multibyte characters.  */
     struct _PDCLIB_status_t status;
     return status.n;
 }
 
+int vfscanf( FILE * _PDCLIB_restrict stream, 
+             const char * _PDCLIB_restrict format, 
+             va_list arg )
+{
+    flockfile( stream );
+    int r = vfscanf_unlocked( stream, format, arg );
+    funlockfile( stream );
+    return r;
+}
+
 #endif
 
 #ifdef TEST
 
 
 #ifndef REGTEST
 
+int vprintf_unlocked( const char * _PDCLIB_restrict format, 
+                      _PDCLIB_va_list arg )
+{
+    return vfprintf_unlocked( stdout, format, arg );
+}
+
 int vprintf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
 {
     return vfprintf( stdout, format, arg );
 
 
 #ifndef REGTEST
 
+int vscanf_unlocked( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
+{
+    return vfscanf_unlocked( stdin, format, arg );
+}
+
 int vscanf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
 {
     return vfscanf( stdin, format, arg );
 
 
 #ifndef REGTEST
 
-int vsnprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
+int vsnprintf( char * _PDCLIB_restrict s, 
+               size_t n, 
+               const char * _PDCLIB_restrict format, 
+               _PDCLIB_va_list arg )
 {
     /* TODO: This function should interpret format as multibyte characters.  */
     struct _PDCLIB_status_t status;
 
 
 #ifndef REGTEST
 
-int vsprintf( char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg )
+int vsprintf( char * _PDCLIB_restrict s, 
+              const char * _PDCLIB_restrict format, 
+              va_list arg )
 {
     return vsnprintf( s, SIZE_MAX, format, arg ); /* TODO: Replace with a non-checking call */
 }
 
 #ifndef REGTEST
 #include <ctype.h>
 
-int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg )
+int vsscanf( const char * _PDCLIB_restrict s, 
+             const char * _PDCLIB_restrict format, 
+             va_list arg )
 {
     /* TODO: This function should interpret format as multibyte characters.  */
     struct _PDCLIB_status_t status;
 
    TODO: Implementation-defined errno setting for ftell().
 */
 long int ftell( FILE * stream ) _PDCLIB_nothrow;
-_PDCLIB_uint_fast64_t _PDCLIB_ftell64( FILE * stream ) _PDCLIB_nothrow;
 
 /* Equivalent to (void)fseek( stream, 0L, SEEK_SET ), except that the error
    indicator for the stream is also cleared.
 int fputs_unlocked(const char *s, FILE *stream);
 #endif
 
+#if defined(_PDCLIB_EXTENSIONS)
+int fgetpos_unlocked( FILE * _PDCLIB_restrict stream, fpos_t * _PDCLIB_restrict pos ) _PDCLIB_nothrow;
+int fsetpos_unlocked( FILE * stream, const fpos_t * pos ) _PDCLIB_nothrow;
+long int ftell_unlocked( FILE * stream ) _PDCLIB_nothrow;
+int fseek_unlocked( FILE * stream, long int offset, int whence ) _PDCLIB_nothrow;
+
+int puts_unlocked( const char * s ) _PDCLIB_nothrow;
+int ungetc_unlocked( int c, FILE * stream ) _PDCLIB_nothrow;
+
+
+int printf_unlocked( const char * _PDCLIB_restrict format, ... ) _PDCLIB_nothrow;
+int vprintf_unlocked( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) _PDCLIB_nothrow;
+int fprintf_unlocked( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... ) _PDCLIB_nothrow;
+int vfprintf_unlocked( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) _PDCLIB_nothrow;
+int scanf_unlocked( const char * _PDCLIB_restrict format, ... ) _PDCLIB_nothrow;
+int vscanf_unlocked( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) _PDCLIB_nothrow;
+int fscanf_unlocked( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... ) _PDCLIB_nothrow;
+int vfscanf_unlocked( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) _PDCLIB_nothrow;
+
+
+// Todo: remove prefix?
+_PDCLIB_uint_fast64_t _PDCLIB_ftell64( FILE * stream ) _PDCLIB_nothrow;
+_PDCLIB_uint_fast64_t _PDCLIB_ftell64_unlocked( FILE * stream ) _PDCLIB_nothrow;
+#endif
+
 _PDCLIB_END_EXTERN_C
 #endif