// // fgets.cpp // // Copyright (c) Microsoft Corporation. All rights reserved. // // Functions that read a string from a file. // #include // Reads a string from a stream. This function reads a string, up to 'count - 1' // characters in length, or until a '\n', whichever is reached first. The string // is always null-terminated on return. The '\n' _is_ written to the string if // it is encountered before space is exhausted. If EOF is encountered immediately, // null is returned. If EOF is encountered after some characters are read, EOF // terminates input just as '\n' would. // // Returns null if the count is nonpositive or if EOF is encountered immediately. // Otherwise, returns the string. template _Success_(return != 0) static Character* __cdecl common_fgets( _Out_writes_z_(count) Character* const string, int const count, __crt_stdio_stream const stream ) throw() { typedef __acrt_stdio_char_traits stdio_traits; _VALIDATE_RETURN(string != nullptr || count == 0, EINVAL, nullptr); _VALIDATE_RETURN(count >= 0, EINVAL, nullptr); _VALIDATE_RETURN(stream.valid(), EINVAL, nullptr); if (count == 0) return nullptr; Character* return_value = nullptr; _lock_file(stream.public_stream()); __try { if (!stdio_traits::validate_stream_is_ansi_if_required(stream.public_stream())) __leave; // Note that we start iterating at 1, so we read at most 'count - 1' // characters from the stream, leaving room for the null terminator: Character* it = string; for (int i = 1; i != count; ++i) { int const c = stdio_traits::getc_nolock(stream.public_stream()); if (c == stdio_traits::eof) { // If we immediately reach EOF before reading any characters, // the C Language Standard mandates that the input buffer should // be left unmodified, so we return immediately, without writing // anything to the buffer: if (it == string) __leave; // Otherwise, when we reach EOF, we just need to stop iterating: break; } // We stop reading when we reach a newline. We do copy the newline: *it++ = static_cast(c); if (static_cast(c) == '\n') break; } *it = '\0'; return_value = string; } __finally { _unlock_file(stream.public_stream()); } __endtry return return_value; } extern "C" char* __cdecl fgets( char* const string, int const count, FILE* const stream ) { return common_fgets(string, count, __crt_stdio_stream(stream)); } extern "C" wchar_t* __cdecl fgetws( wchar_t* const string, int const count, FILE* const stream ) { return common_fgets(string, count, __crt_stdio_stream(stream)); }