blocxx

SafeCStringIO.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2006, Novell, Inc. All rights reserved.
00004 * 
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 * 
00008 *     * Redistributions of source code must retain the above copyright notice,
00009 *       this list of conditions and the following disclaimer.
00010 *     * Redistributions in binary form must reproduce the above copyright
00011 *       notice, this list of conditions and the following disclaimer in the
00012 *       documentation and/or other materials provided with the distribution.
00013 *     * Neither the name of 
00014 *       Vintela, Inc., 
00015 *       nor Novell, Inc., 
00016 *       nor the names of its contributors or employees may be used to 
00017 *       endorse or promote products derived from this software without 
00018 *       specific prior written permission.
00019 * 
00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00030 * POSSIBILITY OF SUCH DAMAGE.
00031 *******************************************************************************/
00032 
00033 
00038 #include "blocxx/BLOCXX_config.h"
00039 #include "blocxx/SafeCStringIO.hpp"
00040 #include "blocxx/SafeCString.hpp"
00041   /* to get OverflowException and RESULT_TRUNCATED */
00042 #include "blocxx/String.hpp"
00043 #include "blocxx/StringBuffer.hpp"
00044 #include "blocxx/IOException.hpp"
00045 #include <cstdio>
00046 
00047 namespace BLOCXX_NAMESPACE
00048 {
00049 namespace SafeCString
00050 {
00051 
00052 char * fgets_trunc(char * dst, std::size_t dstsize, FILE * fp)
00053 {
00054    char * res = std::fgets(dst, dstsize, fp);
00055    if (!res)
00056    {
00057       if (feof(fp))
00058       {
00059          return 0;
00060       }
00061       BLOCXX_THROW(blocxx::IOException, "read error");
00062    }
00063    return res;
00064 }
00065 
00066 char * fgets_check(char * dst, std::size_t dstsize, FILE * fp)
00067 {
00068    std::size_t const end = dstsize - 1;
00069    char savechar = dst[end];
00070    dst[end] = ' '; // anything but '\0'
00071    char * res = std::fgets(dst, dstsize, fp);
00072    char endchar = dst[end];
00073    dst[end] = savechar;
00074    if (res)
00075    {
00076       if (endchar == '\0' && (end == 0 || dst[end - 1] != '\n'))
00077       {
00078          // No newline at end.  Either the input line was truncated, or
00079          // we read the last line of the file and it had no newline.
00080          // We test for EOF to distinguish the two cases.  Since the EOF
00081          // marker doesn't get set until we actually try to read past EOF,
00082          // we first peek one character ahead.
00083          std::ungetc(std::fgetc(fp), fp);
00084          if (!feof(fp))
00085          {
00086             BLOCXX_THROW_ERR(
00087                OverflowException, "fgets overflow", RESULT_TRUNCATED);
00088          }
00089       }
00090       return res;
00091    }
00092    else
00093    {
00094       if (feof(fp))
00095       {
00096          return 0;
00097       }
00098       BLOCXX_THROW(blocxx::IOException, "read error");
00099    }
00100 }
00101 
00102 String fget_string(FILE * fp, std::size_t const max_chars)
00103 {
00104    // This could perhaps be made more efficient by reading directly into a
00105    // custom resizable character array.
00106    std::size_t const BUFSIZE = 8 * 1024;
00107    StringBuffer sb;
00108    char buf[BUFSIZE];
00109    while (!sb.endsWith('\n') && sb.length() <= max_chars &&
00110       fgets_trunc(buf, fp))
00111    {
00112       sb.append(buf);
00113    }
00114    if (sb.length() > max_chars)
00115    {
00116       BLOCXX_THROW(StringConversionException, "input line too long");
00117    }
00118    return sb.releaseString();
00119 }
00120 
00121 } // namespace SafeCString
00122 } // namespace BLOCXX_NAMESPACE