Reactos
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.
21template <typename Character>
22_Success_(return != 0)
23static 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
85extern "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
94extern "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}