Back to index

lightning-sunbird  0.9+nobinonly
nsReadLine.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Boris Zbarsky <bzbarsky@mit.edu>.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Christian Biesinger <cbiesinger@web.de>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #ifndef nsReadLine_h__
00041 #define nsReadLine_h__
00042 
00043 #include "prmem.h"
00044 #include "nsIInputStream.h"
00045 
00064 #define kLineBufferSize 1024
00065 
00070 template<typename CharT>
00071 class nsLineBuffer {
00072   public:
00073   CharT buf[kLineBufferSize+1];
00074   CharT* start;
00075   CharT* current;
00076   CharT* end;
00077   PRBool empty;
00078 };
00079 
00101 template<typename CharT>
00102 nsresult
00103 NS_InitLineBuffer (nsLineBuffer<CharT> ** aBufferPtr) {
00104   *aBufferPtr = PR_NEW(nsLineBuffer<CharT>);
00105   if (!(*aBufferPtr))
00106     return NS_ERROR_OUT_OF_MEMORY;
00107 
00108   (*aBufferPtr)->start = (*aBufferPtr)->current = (*aBufferPtr)->end = (*aBufferPtr)->buf;
00109   (*aBufferPtr)->empty = PR_TRUE;
00110   return NS_OK;
00111 }
00112 
00136 template<typename CharT, class StreamType, class StringType>
00137 nsresult
00138 NS_ReadLine (StreamType* aStream, nsLineBuffer<CharT> * aBuffer,
00139              StringType & aLine, PRBool *more) {
00140   nsresult rv = NS_OK;
00141   PRUint32 bytesRead;
00142   *more = PR_TRUE;
00143   PRBool eolStarted = PR_FALSE;
00144   CharT eolchar = '\0';
00145   aLine.Truncate();
00146   while (1) { // will be returning out of this loop on eol or eof
00147     if (aBuffer->empty) { // buffer is empty.  Read into it.
00148       rv = aStream->Read(aBuffer->buf, kLineBufferSize, &bytesRead);
00149       if (NS_FAILED(rv)) // read failed
00150         return rv;
00151       if (bytesRead == 0) { // end of file
00152         *more = PR_FALSE;
00153         return NS_OK;
00154       }
00155       aBuffer->end = aBuffer->buf + bytesRead;
00156       aBuffer->empty = PR_FALSE;
00157       *(aBuffer->end) = '\0'; // null-terminate this thing
00158     }
00159     // walk the buffer looking for an end-of-line
00160     while (aBuffer->current < aBuffer->end) {
00161       if (eolStarted) {
00162           if ((eolchar == '\n' && *(aBuffer->current) == '\r') ||
00163               (eolchar == '\r' && *(aBuffer->current) == '\n')) { // line end
00164             (aBuffer->current)++;
00165             aBuffer->start = aBuffer->current;
00166           }
00167           eolStarted = PR_FALSE;
00168           return NS_OK;
00169       } else if (*(aBuffer->current) == '\n' ||
00170                  *(aBuffer->current) == '\r') { // line end
00171         eolStarted = PR_TRUE;
00172         eolchar = *(aBuffer->current);
00173         *(aBuffer->current) = '\0';
00174         aLine.Append(aBuffer->start);
00175         (aBuffer->current)++;
00176         aBuffer->start = aBuffer->current;
00177       } else {
00178         eolStarted = PR_FALSE;
00179         (aBuffer->current)++;
00180       }
00181     }
00182 
00183     // append whatever we currently have to the string
00184     aLine.Append(aBuffer->start);
00185 
00186     // we've run out of buffer.  Begin anew
00187     aBuffer->current = aBuffer->start = aBuffer->buf;
00188     aBuffer->empty = PR_TRUE;
00189     
00190     if (eolStarted) {  // have to read another char and possibly skip over it
00191       rv = aStream->Read(aBuffer->buf, 1, &bytesRead);
00192       if (NS_FAILED(rv)) // read failed
00193         return rv;
00194       if (bytesRead == 0) { // end of file
00195         *more = PR_FALSE;
00196         return NS_OK;
00197       }
00198       if ((eolchar == '\n' && *(aBuffer->buf) == '\r') ||
00199           (eolchar == '\r' && *(aBuffer->buf) == '\n')) {
00200         // Just return and all is good -- we've skipped the extra newline char
00201         return NS_OK;
00202       } else {
00203         // we have a byte that we should look at later
00204         aBuffer->empty = PR_FALSE;
00205         aBuffer->end = aBuffer->buf + 1;
00206         *(aBuffer->end) = '\0';
00207       }
00208     }
00209   }
00210 }
00211 
00212 #endif // nsReadLine_h__