Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

mtextstream.cc

Go to the documentation of this file.
00001 
00025 #include "magic/mtextstream.h"
00026 
00027 #include <ctype.h>
00028 #include <math.h>
00029 #include <stdarg.h>
00030 
00031 BEGIN_NAMESPACE (MagiC);
00032 
00033 TextOStream sout (stdout); // Standard output
00034 TextOStream serr (stderr); // Standard error output
00035 TextIStream stin (stdin);  // Standard input
00036 
00037 
00038 /*****************************************************************************/
00043 inline void checkDevice (const IODevice* dev)
00044 {
00045     if (!dev)
00046         throw stream_failure (i18n("Operated stream not associated with a device."));
00047 }
00048 
00050 //            -----                ----                                      //
00051 //              |    ___       |  (      |       ___   ___                   //
00052 //              |   /   ) \ / -+-  ---  -+- |/\ /   )  ___| |/|/|            //
00053 //              |   |---   X   |      )  |  |   |---  (   | | | |            //
00054 //              |    \__  / \   \ ___/    \ |    \__   \__| | | |            //
00056 
00067 void TextStream::copy (const TextStream& other)
00068 {
00069     mFieldWidth = other.mFieldWidth;
00070     mFillChar   = other.mFillChar;
00071     mPrecision  = other.mPrecision;
00072     mBase       = other.mBase;
00073 }
00074 
00075 
00077 //         -----                ___   ----                                   //
00078 //           |    ___       |  |   | (      |       ___   ___                //
00079 //           |   /   ) \ / -+- |   |  ---  -+- |/\ /   )  ___| |/|/|         //
00080 //           |   |---   X   |  |   |     )  |  |   |---  (   | | | |         //
00081 //           |    \__  / \   \ `___´ ___/    \ |    \__   \__| | | |         //
00083 
00084 /*****************************************************************************/
00096 TextOStream::TextOStream (FILE* strm    )
00097         : OStream (strm)
00098 {
00099 }
00100 
00101 /*****************************************************************************/
00104 TextOStream::TextOStream (TextOStream& orig) 
00105         : OStream (orig)
00106 {
00107 }
00108 
00109 /*****************************************************************************/
00119 TextOStream::TextOStream (String& buffer, 
00120                           int mode)
00121         : OStream (buffer, mode)
00122 {
00123 }
00124 
00126 TextOStream& TextOStream::printf (const char* sformat, ...)
00127 {
00128     if (!mpDevice)
00129         return *this;
00130 
00131     va_list args;
00132     va_start (args, sformat);
00133 
00134     // Sprint to a buffer first.
00135     String buffer = vstrformat (sformat, args);
00136 
00137     // Write the buffer to the device
00138     mpDevice->writeBlock (buffer);
00139     
00140     va_end (args);
00141     
00142     if (isAutoFlush())
00143       mpDevice->flush();
00144 
00145    return *this;
00146 }
00147 
00148 void TextOStream::copy (const TextOStream& other)
00149 {
00150     OStream::copy (other);
00151     TextStream::copy (other);
00152 }
00153 
00155 TextOStream& TextOStream::operator<< (const char* str)
00156 {
00157     if (mpDevice)
00158         mpDevice->writeBlock (str, strlen (str));
00159     return *this;
00160 }
00161 
00162 TextOStream& TextOStream::operator<< (const char c)
00163 {
00164     if (mpDevice)
00165         mpDevice->putch (c);
00166     return *this;
00167 }
00168 
00169 TextOStream& TextOStream::operator<< (int x)
00170 {
00171     if (mpDevice)
00172         mpDevice->writeBlock (String(x));
00173     return *this;
00174 }
00175 
00176 TextOStream& TextOStream::operator<< (long x)
00177 {
00178     if (mpDevice)
00179         mpDevice->writeBlock (String(x));
00180     return *this;
00181 }
00182 
00183 TextOStream& TextOStream::operator<< (float x)
00184 {
00185     if (mpDevice)
00186         mpDevice->writeBlock (String(x));
00187     return *this;
00188 }
00189 
00190 TextOStream& TextOStream::operator<< (double x)
00191 {
00192     if (mpDevice)
00193         mpDevice->writeBlock (String(x));
00194     return *this;
00195 }
00196 
00197 TextOStream& TextOStream::operator<< (const String& str)
00198 {
00199     if (mpDevice)
00200         mpDevice->writeBlock (str);
00201     return *this;
00202 }
00203 
00204 uint TextOStream::writeRawBytes (const char* str, uint length)
00205 {
00206     if (mpDevice)
00207         return mpDevice->writeBlock (str, length);
00208 
00209     return 0;
00210 }
00211 
00212 
00213 
00215 //                                                                           //
00216 //          -----               ---  ----                                    //
00217 //            |    ___       |   |  (      |       ___   ___                 //
00218 //            |   /   ) \ / -+-  |   ---  -+- |/\ /   )  ___| |/|/|          //
00219 //            |   |---   X   |   |      )  |  |   |---  (   | | | |          //
00220 //            |    \__  / \   \ _|_ ___/    \ |    \__   \__| | | |          //
00221 //                                                                           //
00223 
00225 TextIStream& TextIStream::operator>> (char& rCh)
00226 {
00227     checkDevice (mpDevice);
00228 
00229     // This is simple, just read the character
00230     rCh = mpDevice->getch ();
00231 
00232     return *this;
00233 }
00234 
00236 TextIStream& TextIStream::operator>> (long& rValue)
00237 {
00238     /* This function is exactly same as above. Any way to remove the redundancy? */
00239        
00240     checkDevice (mpDevice);
00241 
00242     //  We need to read the value character by character.
00243     rValue = 0;
00244     int sign = 1; // Positive
00245     while (! mpDevice->atEnd()) {
00246         char ch = mpDevice->getch ();
00247 
00248         if (isdigit(ch))
00249             rValue = rValue*10 + long (ch - '0'); // The character is a digit; add it to the value.
00250         else if (ch == '-')
00251             sign = -1;
00252         else if (ch == '+')
00253             sign = 1;
00254         else {
00255             // It wasn't a digit, so we didn't want to read it.
00256             mpDevice->ungetch (ch);
00257             break;
00258         }
00259     }
00260 
00261     rValue *= sign;
00262     
00263     return *this;
00264 }
00265 
00267 TextIStream& TextIStream::operator>> (int& rValue)
00268 {
00269 
00270     // Read the value as double-precision
00271     long lvalue = 0;
00272     *this >> lvalue;
00273 
00274     // Convert it
00275     rValue = int (lvalue);
00276     
00277     return *this;
00278 }
00279 
00293 TextIStream& TextIStream::operator>> (double& rValue)
00294 {
00295     checkDevice (mpDevice);
00296 
00297     // We parse the value with a state machine
00298     enum   states {NONE, SIGNFOUND, DOTFOUND, EXPFOUND, EXPSIGNFOUND, END} state = NONE;
00299     char   ch      = 0;     // Character read from device
00300     int    sign    = 1;     // Positive
00301     double fract   = 1.0;   // Multiplier for past-dot digits
00302     int    exp     = 0;     // Exponent
00303     int    expsign = 1;     // Sign of the exponent
00304 
00305     // Skip whitespace
00306     ch = mpDevice->getch ();
00307     while (isspace (ch))
00308         ch = mpDevice->getch ();
00309     
00310     //  Read the value character by character, until value ends, or EOF.
00311     rValue = 0;
00312     while ((!mpDevice->atEnd()) && (state != END)) {
00313         // If the character is a digit, add it to the value
00314         switch (state) {
00315           case NONE:
00316               // Check for sign
00317               if (state == NONE && ch == '-') {
00318                   sign = -1;
00319                   break;
00320               } else if (state == NONE && ch == '+') {
00321                   sign = 1;
00322                   break;
00323               }
00324               state = SIGNFOUND; // It wasn't sign, so it might be a number.
00325               // Fall through:
00326               
00327           case SIGNFOUND:
00328               if (isdigit(ch)) {
00329                   rValue = rValue*10.0 + float (ch - '0');
00330               } else if (ch == '.')
00331                   state = DOTFOUND;
00332               else if (ch == 'e' || ch == 'E')
00333                   state = EXPFOUND;
00334               else
00335                   state = END;
00336               break;
00337               
00338           case DOTFOUND:
00339               if (isdigit (ch)) {
00340                   // Handle post-comma digit
00341                   fract /= 10.0;
00342                   rValue = rValue + double (ch - '0')*fract;
00343               } else if (ch == 'e' || ch == 'E')
00344                   state = EXPFOUND;
00345               else
00346                   state = END;
00347               break;
00348               
00349           case EXPFOUND:
00350               // Check for sign
00351               if (ch == '-') {
00352                   expsign = -1;
00353                   break;
00354               } else if (ch == '+') {
00355                   expsign = 1;
00356                   break;
00357               }
00358               state = EXPSIGNFOUND; // It wasn't sign, so it might be a number.
00359               // Fall through:
00360               
00361           case EXPSIGNFOUND:
00362               if (isdigit(ch))
00363                   exp = exp*10 + int (ch - '0');
00364               else
00365                   state = END;
00366               break;
00367 
00368           case END:
00369               break;
00370         };
00371 
00372         // Read the next character
00373         ch = mpDevice->getch ();
00374     }
00375 
00376     if (state == END) {
00377         // It wasn't a digit, so we didn't want to read it.
00378         mpDevice->ungetch (ch);
00379     }
00380     
00381     // Correct the sign
00382     rValue *= sign;
00383 
00384     // Apply exponent
00385     if (exp != 0)
00386         rValue *= pow (10, double (exp*expsign));
00387     
00388     return *this;
00389 }
00390 
00404 TextIStream& TextIStream::operator>> (float& rValue)
00405 {
00406     // Read the value as double-precision
00407     double dvalue = 0.0;
00408     *this >> dvalue;
00409 
00410     // Convert it
00411     rValue = float (dvalue);
00412     
00413     return *this;
00414 }
00415 
00422 TextIStream& TextIStream::operator>> (String& str)
00423 {
00424     // Use the object's operation.
00425     //str.String::operator<< (*this);
00426     str.operator<< (*this);
00427     
00428     return *this;
00429 }
00430 
00431 /*****************************************************************************/
00434 TextIStream& TextIStream::read (char* p, 
00435                                 int n    )
00436 {
00437     String buffer;
00438     buffer << *this;
00439 
00440     if ((buffer.length() > 0) && (n > 0))
00441         strncpy (p,
00442                  (CONSTR) buffer,
00443                  (uint(n) > buffer.length())? buffer.length() : n);
00444     
00445     return *this;
00446 }
00447 
00448 /*****************************************************************************/
00451 uint TextIStream::readRawBytes (char* data,
00452                                uint maxlen)
00453 {
00454     if (mpDevice)
00455         return mpDevice->readBlock (data, maxlen);
00456     else
00457         return 0;
00458 }
00459 
00465 int TextIStream::readLine (String& linebuf)
00466 {
00467     if (!mpDevice || !mpDevice->isOpen() || mpDevice->atEnd())
00468         return 0;
00469 
00470     linebuf.empty ();
00471 
00472     // Read line in chunks
00473     char buffer [1024+1];
00474     int bytesRead = 0;
00475     int totalRead = 0;
00476     while ((bytesRead = mpDevice->readLine (buffer, 1024))) {
00477         linebuf.append (buffer);
00478         totalRead += bytesRead;
00479 
00480         // If bytes read was 1024 bytes, there may be more.
00481         // WARNING: Should we check if the last byte is newline???
00482         if (bytesRead < 1024)
00483             break;
00484     }
00485 
00486     return totalRead;
00487 }
00488 
00489 END_NAMESPACE;
00490 
00491 

Generated on Thu Feb 10 20:06:42 2005 for LibMagiC by doxygen1.2.18