| | |
detecting '\n' without using getline
Please support our C++ advertiser: Intel Parallel Studio Home
![]() |
Hi all,
I've written a configuration file parser, which is just basically gets a bunch of rules, each ended by ';'
To get the rules I use a loop:
and so on, pretty standard stuff. The problem is, every time I detect an error, all I can do is print the rule number, and not the line number, which means I have to then count the rules by hand to find the erroneous line, because >> ignores whitespace. Is there any way around this short of rewriting the function to use getline?
Is there some stream builtin that will give me a character number, or line number where I am up to in the stream?
All I can think of currently is to use a macro to get the input, and check for '\n':
(I've removed the \ to make it look nicer, and I haven't tested it, but you get the idea
and then just do:
which makes my function look nice, except that I have to use an ugly macro. Mayby I should just use getline - thoughts?
thanks heaps.
I've written a configuration file parser, which is just basically gets a bunch of rules, each ended by ';'
To get the rules I use a loop:
C++ Syntax (Toggle Plain Text)
ifstream cfgFile; for (int iI = 0; iI < iMAX_MONITORS; iI ++) { ... cfgFile >> someFloat; // test for error cfgFile >> someInt; // test for error ... }
and so on, pretty standard stuff. The problem is, every time I detect an error, all I can do is print the rule number, and not the line number, which means I have to then count the rules by hand to find the erroneous line, because >> ignores whitespace. Is there any way around this short of rewriting the function to use getline?
Is there some stream builtin that will give me a character number, or line number where I am up to in the stream?
All I can think of currently is to use a macro to get the input, and check for '\n':
(I've removed the \ to make it look nicer, and I haven't tested it, but you get the idea

C++ Syntax (Toggle Plain Text)
#define EXPECT_INPUT(input, msg) { cfgFile >> input; if (!cfgFile) { if (cfgFile.eof ()) { break; } printf ("error \"%s\" in config file, rule %d, line %d.", msg, iI + 1, iLines + 1); cfgFile.clear(); cfgFile.ignore(std::numeric_limits<streamsize>::max(),';'); break; } do { c=cfgFile.peek(); if (c == '\n') iLines ++; if (c==' ' || c=='\n') c=cfgFile.get(); } while (c==' ' || c=='\n'); }
and then just do:
EXPECT_INPUT (someFloat, "a number");
EXPECT_INPUT (charArray, "a string");
which makes my function look nice, except that I have to use an ugly macro. Mayby I should just use getline - thoughts?
thanks heaps.
--
Perfection is reached, not when there is no longer anything to add, but when there is no longer anything to take away.
-- Antoine de Saint-Exupery
Perfection is reached, not when there is no longer anything to add, but when there is no longer anything to take away.
-- Antoine de Saint-Exupery
Step 1 would be to redo that horrible macro as a proper C++ function.
There are very few valid reasons (struggling to think of one ATM) where using a function-like macro is the best approach. Inline functions and templates cover a lot of the things which were done as macros in C.
Step 2: Then consider implementing a small configFile class, which hides some of the detail (how the file is read), and can provide line:column information via a suitable member function.
Whether you then use getline(), or the code you have then no longer matters to the bulk of the code.
You could then implement other value services, say read a rule.
There are very few valid reasons (struggling to think of one ATM) where using a function-like macro is the best approach. Inline functions and templates cover a lot of the things which were done as macros in C.
Step 2: Then consider implementing a small configFile class, which hides some of the detail (how the file is read), and can provide line:column information via a suitable member function.
Whether you then use getline(), or the code you have then no longer matters to the bulk of the code.
You could then implement other value services, say read a rule.
OK I re-wrote the macro as a function template, however I came into a problem, which the macro didn't have:
I passed as an arg to the macro an extra "test":
and then for the macro call I could say:
How do I overcome this? Don't move the test to the function template? Seems like a bit of code duplication.
Also, it still hasn't overcome how I detect a '\n' and hence count lines!
Do I use tellg()? Or the concept from my original macro of sucking up and testing whitespace, but in the function template?
Your brutal honesty is appreciated
thanks again.
I passed as an arg to the macro an extra "test":
C++ Syntax (Toggle Plain Text)
#define EXPECT_INPUT(input, test) { cfgFile >> input; if (!cfgFile || test) { if (cfgFile.eof ()) { break; } ...
EXPECT_INPUT(someChar, (someChar != 'a')); and the test would be done inline, but I can't do that with a function, because the arguement is evaluated before it's passed: C++ Syntax (Toggle Plain Text)
template <class input> void HandleInput (ifstream *poF, input &oI, bool bTest2 = false) { (*poF) >> oI; ... } ... void HandleInput (cfgFile, someChar, someChar != 'a');
Also, it still hasn't overcome how I detect a '\n' and hence count lines!
Do I use tellg()? Or the concept from my original macro of sucking up and testing whitespace, but in the function template?
Your brutal honesty is appreciated

thanks again.
--
Perfection is reached, not when there is no longer anything to add, but when there is no longer anything to take away.
-- Antoine de Saint-Exupery
Perfection is reached, not when there is no longer anything to add, but when there is no longer anything to take away.
-- Antoine de Saint-Exupery
OK, the "test" is easy, I can just set up a parameter with a default value
as it turns out all my tests were only when I am reading a single character. But still not sure about a more elegant way of detecting '\n'.
C++ Syntax (Toggle Plain Text)
template <class input> void HandleInput (ifstream *poF, input &oI, char test = '\0') ... if (test != '\0') ...
--
Perfection is reached, not when there is no longer anything to add, but when there is no longer anything to take away.
-- Antoine de Saint-Exupery
Perfection is reached, not when there is no longer anything to add, but when there is no longer anything to take away.
-- Antoine de Saint-Exupery
•
•
Join Date: Dec 2006
Posts: 1,089
Reputation:
Solved Threads: 164
>> and then for the macro call I could say ... and the test would be done inline,
>> but I can't do that with a function, because the arguement is evaluated before it's passed:
use a function object (or a pointer to a function; not as flexible or efficient) to encapsulate a unit of procedural code.
>> still not sure about a more elegant way of detecting '\n'.
use composition; wrap a helper class which counts lines around the stream.
you could use boost.iostream and boost.lambda; the code would then look more elegant.
>> but I can't do that with a function, because the arguement is evaluated before it's passed:
use a function object (or a pointer to a function; not as flexible or efficient) to encapsulate a unit of procedural code.
>> still not sure about a more elegant way of detecting '\n'.
use composition; wrap a helper class which counts lines around the stream.
C++ Syntax (Toggle Plain Text)
#include <iostream> #include <fstream> #include <functional> using namespace std ; template< typename ISTREAM > struct line_count_wrapper { explicit line_count_wrapper( ISTREAM& s ) : stm(s), line(1) {} int current_line() const { return line ; } template< typename T > line_count_wrapper<ISTREAM>& operator>> ( T& v ) { eatwhite() ; stm >> v ; return *this ; } bool operator!() { return !stm ; } operator void* () { return stm ; } private: int line ; ISTREAM& stm ; void eatwhite() { char ch ; while( stm.get(ch) && isspace(ch) ) if( ch == '\n' ) ++line ; if(stm) stm.putback(ch) ; } // non-copyable; do do not define these line_count_wrapper( const line_count_wrapper& ) ; void operator= ( const line_count_wrapper& ) ; }; template< typename LCSTM, typename T, typename TEST > inline bool handle_input( LCSTM& stm, T& input, TEST test_error, const char* msg ) { if(!( stm >> input ) ) return false ; if ( test_error(input) ) { cerr << "error " << msg << " at line " << stm.current_line() << '\n' ; return false ; } return true ; } int main() { int i ; double d ; ifstream file( "config.txt" ) ; line_count_wrapper<istream> stm(file) ; while( stm ) { handle_input( stm, i, bind2nd( equal_to<int>(), 0 ), "int is zero" ) ; handle_input( stm, d, bind2nd( less<double>(), 0.0 ), "double is -ve" ) ; } } /** config.txt 45 89.3 34 -23.7 0 56.7 0 -34.8 23 42.5 8 -67.2 */ /** output error double is -ve at line 2 error int is zero at line 3 error int is zero at line 5 error double is -ve at line 5 error double is -ve at line 7 */
•
•
Join Date: Dec 2006
Posts: 1,089
Reputation:
Solved Threads: 164
c provides escape sequences '\n' and '\r'. contrary to popular belief, these are not required to be equivalent to specific control characters. the c standard guarantees that 1. each of these escape sequences maps to a unique implementation-defined number that can be stored in a single char. 2. when writing a file in text mode, '\n' is transparently translated to the native newline sequence on the the system (which may be longer than one character). when reading in text mode, the native newline sequence is translated back to '\n'. (in binary i/o mode, no such translation is performed.) c++ also provides L'\n' and L'\r'; these are the wchar_t equivalents.
so, looking for '\n' is correct if the char_type of the stream is a char. to also handle other char_types (eg. wchar_t), basic_ios<char_type,traits_types>::widen('\n') could be used.
so, looking for '\n' is correct if the char_type of the stream is a char. to also handle other char_types (eg. wchar_t), basic_ios<char_type,traits_types>::widen('\n') could be used.
Last edited by vijayan121; Sep 10th, 2007 at 3:43 pm.
•
•
Join Date: Dec 2006
Posts: 1,089
Reputation:
Solved Threads: 164
using '\n' is ok if we are sure that the char_type of the stream is a char. to also take care of all char_types (including user-defined char_types), we should modify the code to
this may not be very appropriate code to show to a student who is just starting out with c++.
C++ Syntax (Toggle Plain Text)
void eatwhite() { typedef typename ISTREAM::char_type char_type ; ctype<char_type> facet = use_facet< ctype<char_type> >( stm.getloc() ) ; char_type ch ; while( stm.get(ch) && facet.is( ctype_base::space, ch ) ) if( ch == facet.widen('\n') ) ++line ; if(stm) stm.putback(ch) ; }
Last edited by vijayan121; Sep 10th, 2007 at 4:19 pm.
I can't seem to get your example to work, what am I doing wrong?
??
C++ Syntax (Toggle Plain Text)
thwee@thwee-desktop:~$ g++ -Wall pedantic.cc pedantic.cc: In constructor ‘line_count_wrapper<ISTREAM>::line_count_wrapper(ISTREAM&) [with ISTREAM = std::basic_istream<char, std::char_traits<char> >]’: pedantic.cc:50: instantiated from here pedantic.cc:20: warning: ‘line_count_wrapper<std::basic_istream<char, std::char_traits<char> > >::stm’ will be initialized after pedantic.cc:19: warning: ‘int line_count_wrapper<std::basic_istream<char, std::char_traits<char> > >::line’ pedantic.cc:8: warning: when initialized here
![]() |
Similar Threads
- cin.getline (C++)
- Windows 98 SE not detecting onboard ethernet (Windows 95 / 98 / Me)
- why i have to press "enter" twice before getline can read the string... (C++)
- need help problem with cin.getline method (C++)
Other Threads in the C++ Forum
- Previous Thread: I need help with a program!!
- Next Thread: Help needed with parrallel arrays/array of classes
Views: 2971 | Replies: 11
| Thread Tools | Search this Thread |
Tag cloud for C++
6 api application array arrays assignment beginner binary bitmap c++ c/c++ calculator char class classes code coding compile compiler console conversion convert count data database delete developer display dll email encryption error file forms fstream function functions game generator getline givemetehcodez graph homeworkhelper iamthwee ifstream image input int integer java lazy lib loop looping loops map math matrix memory multidimensional multiple newbie news node number output parameter pointer problem program programming project proxy python random read recursion recursive reference return sort string strings struct template templates text tree url variable vector video visual visualstudio win32 windows winsock word wordfrequency wxwidgets






