1 // 2 // fgets.cpp 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Functions that read a string from a file. 7 // 8 #include <corecrt_internal_stdio.h> 9 10 11 12 // Reads a string from a stream. This function reads a string, up to 'count - 1' 13 // characters in length, or until a '\n', whichever is reached first. The string 14 // is always null-terminated on return. The '\n' _is_ written to the string if 15 // it is encountered before space is exhausted. If EOF is encountered immediately, 16 // null is returned. If EOF is encountered after some characters are read, EOF 17 // terminates input just as '\n' would. 18 // 19 // Returns null if the count is nonpositive or if EOF is encountered immediately. 20 // Otherwise, returns the string. 21 template <typename Character> 22 _Success_(return != 0) 23 static Character* __cdecl common_fgets( 24 _Out_writes_z_(count) Character* const string, 25 int const count, 26 __crt_stdio_stream const stream 27 ) throw() 28 { 29 typedef __acrt_stdio_char_traits<Character> stdio_traits; 30 31 _VALIDATE_RETURN(string != nullptr || count == 0, EINVAL, nullptr); 32 _VALIDATE_RETURN(count >= 0, EINVAL, nullptr); 33 _VALIDATE_RETURN(stream.valid(), EINVAL, nullptr); 34 35 if (count == 0) 36 return nullptr; 37 38 Character* return_value = nullptr; 39 40 _lock_file(stream.public_stream()); 41 __try 42 { 43 if (!stdio_traits::validate_stream_is_ansi_if_required(stream.public_stream())) 44 __leave; 45 46 // Note that we start iterating at 1, so we read at most 'count - 1' 47 // characters from the stream, leaving room for the null terminator: 48 Character* it = string; 49 for (int i = 1; i != count; ++i) 50 { 51 int const c = stdio_traits::getc_nolock(stream.public_stream()); 52 if (c == stdio_traits::eof) 53 { 54 // If we immediately reach EOF before reading any characters, 55 // the C Language Standard mandates that the input buffer should 56 // be left unmodified, so we return immediately, without writing 57 // anything to the buffer: 58 if (it == string) 59 __leave; 60 61 // Otherwise, when we reach EOF, we just need to stop iterating: 62 break; 63 } 64 65 // We stop reading when we reach a newline. We do copy the newline: 66 *it++ = static_cast<Character>(c); 67 if (static_cast<Character>(c) == '\n') 68 break; 69 } 70 71 *it = '\0'; 72 return_value = string; 73 } 74 __finally 75 { 76 _unlock_file(stream.public_stream()); 77 } 78 __endtry 79 80 return return_value; 81 } 82 83 84 85 extern "C" char* __cdecl fgets( 86 char* const string, 87 int const count, 88 FILE* const stream 89 ) 90 { 91 return common_fgets(string, count, __crt_stdio_stream(stream)); 92 } 93 94 extern "C" wchar_t* __cdecl fgetws( 95 wchar_t* const string, 96 int const count, 97 FILE* const stream 98 ) 99 { 100 return common_fgets(string, count, __crt_stdio_stream(stream)); 101 } 102