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

wvprotostream.cc

Go to the documentation of this file.
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvProtoStream is a framework that makes it easy to communicate using
00006  * common command-response driven protocols.  This is supposed to be flexible
00007  * enough to handle FTP, HTTP, SMTP, tunnelv, Weaver rcmd, and many others.
00008  */
00009 #include "wvprotostream.h"
00010 #include "wvlog.h"
00011 #include "strutils.h"
00012 #include <ctype.h>
00013 #include <assert.h>
00014 
00015 
00016 WvProtoStream::WvProtoStream(WvStream **_cloned, WvLog *_debuglog)
00017                 : WvStreamClone(_cloned)
00018 {
00019     if (_debuglog)
00020         logp = new WvLog(_debuglog->split(WvLog::Debug3));
00021     else
00022         logp = NULL;
00023     
00024     log_enable = true;
00025     state = 0;
00026 }
00027 
00028 
00029 WvProtoStream::~WvProtoStream()
00030 {
00031     if (logp) delete logp;
00032 }
00033 
00034 
00035 /* Just like a WvStream::uwrite(), but it copies all output to WvLog if
00036  * log_enable==true.
00037  */
00038 size_t WvProtoStream::uwrite(const void *buf, size_t size)
00039 {
00040     if (logp && log_enable)
00041     {
00042         (*logp)("Sent: ");
00043         logp->write(buf, size);
00044         (*logp)("\n");
00045     }
00046     
00047     return WvStreamClone::uwrite(buf, size);
00048 }
00049 
00050 
00051 WvProtoStream::Token *WvProtoStream::next_token()
00052 {
00053     static unsigned char whitespace[] = " \t\r\n";
00054     size_t len;
00055     
00056     // find and remove up to first non-whitespace
00057     tokbuf.get(tokbuf.match(whitespace, sizeof(whitespace)));
00058 
00059     // return a token up to the first whitespace character
00060     len = tokbuf.match(whitespace, sizeof(whitespace), true);
00061     return len ? new Token(tokbuf.get(len), len) : NULL;
00062 }
00063 
00064 
00065 WvString WvProtoStream::next_token_str()
00066 {
00067     Token *t = next_token();
00068     if (!t) return WvString("");
00069     
00070     WvString s(t->data);
00071     delete t;
00072     return s;
00073 }
00074 
00075 
00076 WvString WvProtoStream::token_remaining()
00077 {
00078     tokbuf.put("", 1);
00079     return trim_string((char *)tokbuf.get(tokbuf.used()));
00080 }
00081 
00082 
00083 /* Default input tokenizer.  "line" is NULL-terminated, and individual string
00084  * tokens are separated by any amount of whitespace.
00085  */
00086 WvProtoStream::TokenList *WvProtoStream::tokenize()
00087 {
00088     TokenList *tl = new TokenList;
00089     Token *t;
00090 
00091     while ((t = next_token()) != NULL)
00092         tl->append(t, true);
00093 #if 0 
00094     if (logp && log_enable && tl->count())
00095     {
00096         (*logp)("Read: ");
00097         TokenList::Iter i(*tl);
00098         for (i.rewind(); i.next(); )
00099             (*logp)("(%s) ", i.data);
00100         (*logp)("\n");
00101     }
00102 #endif
00103     return tl;
00104 }
00105 
00106 
00107 /* convert a TokenList to an array of Token.
00108  * The TokenList becomes invalid after this operation!
00109  * Remember to free the array afterwards!
00110  */
00111 size_t WvProtoStream::list_to_array(TokenList *tl, Token **array)
00112 {
00113     size_t total = tl->count(), count;
00114     
00115     assert(array);
00116     *array = new Token[total];
00117     
00118     TokenList::Iter i(*tl);
00119     for (count = 0, i.rewind(); i.next(); count++)
00120     {
00121         Token &t = i;
00122         (*array)[count].fill((unsigned char *)(const char *)t.data, t.length);
00123     }
00124     
00125     delete tl;
00126     return count;
00127 }
00128 
00129 
00130 /* Retrieve an input line and parse its first token.
00131  * This is the usual high-level interface to the input tokenizer. Remember
00132  * to free the array afterwards!
00133  * Ths input line is specifically allowed to be a NULL pointer.  In that case,
00134  * the returned token will be NULL also.
00135  */
00136 WvProtoStream::Token *WvProtoStream::tokline(const char *line)
00137 { 
00138     if (!line) return NULL;
00139     
00140     char *newline = strdup(line);
00141     
00142     tokbuf.zap();
00143     tokbuf.put(line, strlen(line));
00144 
00145     if (strlen(trim_string(newline)) > 0)
00146         (*logp)("Read: %s\n", trim_string(newline));
00147     
00148     free(newline);
00149     
00150     return next_token();
00151 }
00152 
00153 
00154 /* returns -1 if t is not in lookup[], or else the index into lookup where
00155  * the token was found.
00156  */
00157 int WvProtoStream::tokanal(const Token &t, char **lookup,
00158                            bool case_sensitive)
00159 {
00160     assert(lookup);
00161     
00162     char **i;
00163     
00164     for (i = lookup; *i; i++)
00165     {
00166         if ( (!case_sensitive && !strcasecmp(t.data, *i))
00167           || ( case_sensitive && !strcmp(t.data, *i)) )
00168             return i - lookup;
00169     }
00170     
00171     return -1;
00172 }
00173 
00174 
00175 void WvProtoStream::do_state(Token &)
00176 {
00177 }
00178 
00179 
00180 void WvProtoStream::switch_state(int newstate)
00181 {
00182     state = newstate;
00183 }
00184 
00185 
00186 /* Default execute() function -- process a line of input, and handle it
00187  * (based on the current system state) using do_state().
00188  */
00189 void WvProtoStream::execute()
00190 {
00191     WvStreamClone::execute();
00192     
00193     Token *t1 = tokline(getline(0));
00194     
00195     if (t1)
00196     {
00197         do_state(*t1);
00198         delete t1;
00199     }
00200 }
00201 
00202 
00203 
00205 
00206 
00207 
00208 WvProtoStream::Token::Token()
00209 {
00210     // leave empty -- you should call fill() manually later!
00211 }
00212 
00213 
00214 WvProtoStream::Token::Token(const unsigned char *_data, size_t _length)
00215 {
00216     fill(_data, _length);
00217 }
00218 
00219 
00220 void WvProtoStream::Token::fill(const unsigned char *_data,
00221                                 size_t _length)
00222 {
00223     length = _length;
00224     
00225     data.setsize(length + 1);
00226     memcpy(data.edit(), _data, length);
00227     data.edit()[length] = 0;
00228 }
00229 
00230 
00231 WvProtoStream::Token::~Token()
00232 {
00233     // 'data' member is freed automatically
00234 }

Generated on Sat Aug 24 21:37:01 2002 for WvStreams by doxygen1.2.15