contrib/mul/mbl/mbl_parse_block.cxx
Go to the documentation of this file.
00001 // This is mul/mbl/mbl_parse_block.cxx
00002 #include "mbl_parse_block.h"
00003 //:
00004 // \file
00005 // \author Ian Scott
00006 // \date  25-Feb-2003
00007 // \brief Load a block of text from a file.
00008 
00009 #include <vcl_cctype.h>
00010 #include <vcl_cstring.h>
00011 #include <vcl_iostream.h>
00012 #include <mbl/mbl_exception.h>
00013 
00014 //: Read a block of text from a stream.
00015 // This function will read through a stream, and store the text found to a string.
00016 // The function terminates when it finds the closing brace.
00017 //
00018 // The stream's fail bit will be set on error. Comment lines beginning with //
00019 // will be stripped.
00020 // \param open_already should be true if the client has already
00021 // read the opening brace. If set to false and the first non-whitespace character is
00022 // not an opening brace then that character will be left in the stream and "{} will be returned.
00023 // \return the text including the opening and closing braces.
00024 // \param comment Lines beginning with white space followed by this string will be ignored.
00025 // \throws mbl_exception_parse_block_parse_error if unrecoverable parse error.
00026 // Set to empty for no comment stripping.
00027 
00028 vcl_string mbl_parse_block(vcl_istream &afs, bool open_already /*= false*/, const char * comment /*= "//"*/)
00029 {
00030   if (!afs) return "{}";
00031   //: The last character to be read from the stream
00032   char c;
00033 
00034   // length of the comment token;
00035   const unsigned comment_length = vcl_strlen(comment);
00036 
00037   if (!open_already)
00038   {
00039     if (afs.eof())
00040       return "{}";
00041     afs >> c;
00042 
00043     if (!afs) return "{}";
00044     while (comment && comment_length && c == *comment)
00045     {
00046       for (unsigned comment_pos=1; comment_pos < comment_length; ++comment_pos)
00047       {
00048         if (afs.eof())
00049           return "{}";
00050         afs >> c;
00051         if (c != comment[comment_pos])
00052         {
00053           afs.putback(c); // push c back into stream.
00054           return "{}";
00055         }
00056       }
00057       vcl_string dummy;
00058       vcl_getline(afs, dummy);
00059       if (afs.eof())
00060         return "{}";
00061       afs >> vcl_ws >> c;
00062     }
00063     if (c != '{')
00064     {
00065       afs.putback(c); // push c back into stream.
00066       return "{}";
00067     }
00068   }
00069   // The stored string.
00070   vcl_string s="{";
00071   // The current line is stored separately
00072   // before being added to s, in case it turns out to be a comment.
00073   vcl_string s2="";
00074   // The number of open braces.
00075   unsigned level=1;
00076   // The current position in a comment token.
00077   unsigned comment_position=0;
00078   // true if we are currently in the whitespace at the beginning of a line
00079   bool newline=true;
00080 
00081   while (!(!afs))
00082   {
00083     // read in one line at a time, to make decisions about comments
00084     while (!(!afs))
00085     {
00086       afs.get(c);
00087       s2 += c;
00088       if (c=='\n')
00089       {
00090         s+=s2;
00091         s2="";
00092         newline = true;
00093         comment_position = 0;
00094       }
00095       else if (vcl_isspace(c))
00096         comment_position = 0;
00097       else if (newline && comment_position < comment_length
00098                &&  c==comment[comment_position])
00099       {
00100         if (++comment_position == 2)
00101         {
00102           vcl_string dummy;
00103           vcl_getline(afs, dummy);
00104           s2 = "";
00105           newline = true; //false;
00106           comment_position = 0;
00107         }
00108       }
00109       else
00110       {
00111         newline = false;
00112         comment_position = 0;
00113         if (c=='{') ++level;
00114         else if (c=='}')
00115           if (--level==0) // Found final closing brace
00116           {
00117             s+=s2;
00118             for (unsigned i = 1; i+1 < s.size(); ++i)
00119               if (!vcl_isspace(s[i])) return s;
00120             // Contents between braces is just empty space
00121             return "{}";
00122           }
00123       }
00124     }
00125   }
00126   mbl_exception_warning(mbl_exception_parse_block_parse_error(
00127     "Read problem (possibly end-of-file) before closing '}'\n",s));
00128   afs.clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00129   return "{}";
00130 }