00001
00024 #include "libport/windows.hh"
00025
00026 #include "libport/cstdio"
00027 #include <cstdlib>
00028 #include <cerrno>
00029 #include <cmath>
00030 #include "libport/sys/stat.h"
00031
00032 #include <algorithm>
00033 #include <iostream>
00034
00035 #include "urbi/uabstractclient.hh"
00036 #include "libport/lockable.hh"
00037
00038 #define URBI_ERROR_TAG "[error]"
00039 #define URBI_WILDCARD_TAG "[wildcard]"
00040
00041 namespace urbi
00042 {
00043 enum UCallbackType
00044 {
00045 UCB_,
00046 UCB_C,
00047 };
00048
00049 static UCallbackID nextId;
00050
00051 class UCallbackWrapperCB: public UCallbackWrapper
00052 {
00053 UCallback cb;
00054 public:
00055 UCallbackWrapperCB(UCallback cb): cb(cb)
00056 {
00057 }
00058 virtual UCallbackAction operator ()(const UMessage& msg)
00059 {
00060 return cb(msg);
00061 }
00062 };
00063
00064
00065 class UCallbackWrapperCCB: public UCallbackWrapper
00066 {
00067 UCustomCallback cb;
00068 void * data;
00069 public:
00070 UCallbackWrapperCCB(UCustomCallback cb, void * data): cb(cb), data(data)
00071 {
00072 }
00073 virtual UCallbackAction operator ()(const UMessage& msg)
00074 {
00075 return cb(data, msg);
00076 }
00077 };
00078
00079
00080 class UClientStreambuf: public std::streambuf
00081 {
00082 public:
00083 UClientStreambuf(UAbstractClient * cl)
00084 : client(cl)
00085 {
00086 }
00087
00088 protected:
00089 virtual int overflow (int c = EOF);
00090
00091 virtual std::streamsize xsputn (const char* s, std::streamsize n);
00092
00093 private:
00094 UAbstractClient* client;
00095 };
00096
00097 int UClientStreambuf::overflow (int c )
00098 {
00099 if (c != EOF)
00100 {
00101 char ch = c;
00102 xsputn(&ch, 1);
00103 }
00104 return c;
00105 }
00106
00107 std::streamsize UClientStreambuf::xsputn (const char* s, std::streamsize n)
00108 {
00109 client->sendBufferLock.lock();
00110 if (strlen(client->sendBuffer)+1+n > static_cast<unsigned>(client->buflen))
00111 {
00112
00113 client->sendBufferLock.unlock();
00114 return 0;
00115 }
00116 int clen = strlen(client->sendBuffer);
00117 memcpy(client->sendBuffer+clen, s, n);
00118 client->sendBuffer[clen+n] = 0;
00119 if (strchr(client->sendBuffer, '&')
00120 || strchr(client->sendBuffer, '|')
00121 || strchr(client->sendBuffer, ';')
00122 || strchr(client->sendBuffer, ','))
00123 {
00124 client->effectiveSend(client->sendBuffer, strlen(client->sendBuffer));
00125 client->sendBuffer[0] = 0;
00126 }
00127 client->sendBufferLock.unlock();
00128 return n;
00129 }
00130
00131
00132
00136 void
00137 UAbstractClient::notifyCallbacks(const UMessage &msg)
00138 {
00139 listLock.lock();
00140 bool inc=false;
00141 for (std::list<UCallbackInfo>::iterator it = callbackList.begin();
00142 it!=callbackList.end(); inc?it:it++, inc=false)
00143 {
00144 if (STREQ(msg.tag.c_str(), it->tag)
00145 || STREQ(it->tag, URBI_ERROR_TAG) && msg.type == MESSAGE_ERROR
00146 || STREQ(it->tag, URBI_WILDCARD_TAG))
00147 {
00148 UCallbackAction ua = it->callback(msg);
00149 if (ua == URBI_REMOVE)
00150 {
00151 delete &(it->callback);
00152 it=callbackList.erase(it);
00153 inc = true;
00154 }
00155 }
00156 }
00157 listLock.unlock();
00158 }
00159
00166 UAbstractClient::UAbstractClient(const char *_host, int _port, int _buflen)
00167 : std::ostream(new UClientStreambuf(this)),
00168
00169 sendBufferLock(*new libport::Lockable()),
00170 listLock(*new libport::Lockable()),
00171 host (NULL),
00172 port (_port),
00173 buflen (_buflen),
00174 rc (0),
00175
00176 recvBuffer (NULL),
00177 recvBufferPosition (0),
00178
00179 binaryBuffer (NULL),
00180 parsePosition (0),
00181 inString (false),
00182 nBracket (0),
00183 binaryMode(false),
00184 system(false),
00185 uid (0),
00186 stream(this)
00187 {
00188 getStream().setf(std::ios::fixed);
00189 host = new char[strlen(_host) + 1];
00190 if (!host)
00191 {
00192 rc = -1;
00193 return;
00194 }
00195 strcpy(host, _host);
00196
00197 recvBuffer = new char[buflen];
00198 if (!recvBuffer)
00199 {
00200 rc = -1;
00201
00202 return;
00203 }
00204 recvBuffer[0] = 0;
00205
00206 sendBuffer = new char[buflen];
00207 if (!sendBuffer)
00208 {
00209 rc = -1;
00210
00211 return;
00212 }
00213 sendBuffer[0] = 0;
00214 }
00215
00216 UAbstractClient::~UAbstractClient()
00217 {
00218 delete [] host;
00219 delete [] recvBuffer;
00220 delete [] sendBuffer;
00221 }
00222
00227 int
00228 UAbstractClient::startPack()
00229 {
00230 sendBufferLock.lock();
00231 return 0;
00232 }
00233
00234 int
00235 UAbstractClient::endPack()
00236 {
00237 int retval = effectiveSend(sendBuffer, strlen(sendBuffer));
00238 sendBuffer[0] = 0;
00239 sendBufferLock.unlock();
00240 return retval;
00241 }
00242
00243
00246 int
00247 UAbstractClient::send(const char *command, ...)
00248 {
00249 if (rc)
00250 return -1;
00251 va_list arg;
00252 va_start(arg, command);
00253 sendBufferLock.lock();
00254 rc = vpack(command, arg);
00255 va_end(arg);
00256 if (rc < 0)
00257 {
00258 sendBufferLock.unlock();
00259 return rc;
00260 }
00261 rc = effectiveSend(sendBuffer, strlen(sendBuffer));
00262 sendBuffer[0] = 0;
00263 sendBufferLock.unlock();
00264 return rc;
00265 }
00266
00267 int UAbstractClient::send(UValue &v)
00268 {
00269 switch (v.type)
00270 {
00271 case DATA_DOUBLE:
00272 send("%lf", v.val);
00273 break;
00274 case DATA_STRING:
00275 send("\"%s\"", v.stringValue->c_str());
00276 break;
00277 case DATA_BINARY:
00278 if (v.binary->type != BINARY_NONE
00279 && v.binary->type != BINARY_UNKNOWN)
00280 v.binary->buildMessage();
00281 sendBin(v.binary->common.data, v.binary->common.size,
00282 "BIN %d %s;", v.binary->common.size,
00283 v.binary->message.c_str());
00284 break;
00285 case DATA_LIST:
00286 {
00287 send("[");
00288 int sz = v.list->size();
00289 for (int i = 0; i < sz; ++i)
00290 {
00291 send((*v.list)[i]);
00292 if (i != sz-1)
00293 send(" , ");
00294 }
00295 send("]");
00296 }
00297 break;
00298 case DATA_OBJECT:
00299 {
00300 send("OBJ %s [", v.object->refName.c_str());
00301 int sz = v.object->size();
00302 for (int i = 0; i < sz; ++i)
00303 {
00304 send("%s :", (*v.object)[i].name.c_str());
00305 send(*((*v.object)[i].val) );
00306 if (i != sz-1)
00307 send(" , ");
00308 }
00309 send("]");
00310 }
00311 break;
00312 case DATA_VOID:
00313 break;
00314 };
00315 return 0;
00316 }
00317
00318
00319
00324 int
00325 UAbstractClient::pack(const char *command, ...)
00326 {
00327 if (rc)
00328 return -1;
00329 va_list arg;
00330 va_start(arg, command);
00331 rc=vpack(command, arg);
00332 va_end(arg);
00333 return rc;
00334 }
00335
00336
00337 int
00338 UAbstractClient::vpack(const char *command, va_list arg)
00339 {
00340
00341 if (rc)
00342 return -1;
00343 #if 0 //disabled, crashes
00344 int size = vsnprintf(NULL, 0, command, arg);
00345 va_end(arg);
00346 if (strlen(sendBuffer) + size + 1 > buflen)
00347 return -1;
00348 else
00349 {
00350 #endif
00351 sendBufferLock.lock();
00352 vsprintf(&sendBuffer[strlen(sendBuffer)], command, arg);
00353 sendBufferLock.unlock();
00354 va_end(arg);
00355 return 0;
00356 #if 0
00357 }
00358 #endif
00359 }
00360
00361
00362 int
00363 UAbstractClient::sendFile(const char *name)
00364 {
00365 if (rc)
00366 return -1;
00367 FILE *fd;
00368 fd = fopen(name, "r");
00369 if (fd == NULL)
00370 return -1;
00371 int size;
00372 struct stat s;
00373 stat(name, &s);
00374 size = s.st_size;
00375 sendBufferLock.lock();
00376 if (!canSend(size))
00377 {
00378 sendBufferLock.unlock();
00379 return -1;
00380 }
00381
00382 while (!feof(fd))
00383 {
00384 int res = fread(sendBuffer, 1, buflen, fd);
00385 effectiveSend(sendBuffer, res);
00386 }
00387 fclose(fd);
00388 sendBuffer[0] = 0;
00389 sendBufferLock.unlock();
00390 return 0;
00391 }
00392
00393
00394 int
00395 UAbstractClient::sendBin(const void *buffer, int len)
00396 {
00397 return sendBin(buffer, len, NULL, 0);
00398 }
00399
00400
00401 int
00402 UAbstractClient::sendBin(const void *buffer, int len,
00403 const char *header, ...)
00404 {
00405 if (rc)
00406 return -1;
00407 sendBufferLock.lock();
00408 if (header)
00409 {
00410 va_list arg;
00411 va_start(arg, header);
00412 vpack(header, arg);
00413 va_end(arg);
00414 if (!canSend(strlen(sendBuffer) + len))
00415 {
00416 sendBufferLock.unlock();
00417 return -1;
00418 }
00419
00420 effectiveSend(sendBuffer, strlen(sendBuffer));
00421 }
00422
00423 int res = effectiveSend(buffer, len);
00424 sendBuffer[0] = 0;
00425 sendBufferLock.unlock();
00426 return res;
00427 }
00428
00429 struct sendSoundData
00430 {
00431 char * buffer;
00432 int bytespersec;
00433 int length;
00434 int pos;
00435 char * device;
00436 char * tag;
00437 char formatString[50];
00438 USoundFormat format;
00439 UAbstractClient * uc;
00440 bool startNotify;
00441 };
00442
00443 struct wavheader
00444 {
00445 char riff[4];
00446 int length;
00447 char wave[4];
00448 char fmt[4];
00449 int lnginfo;
00450 short one;
00451 short channels;
00452 int freqechant;
00453 int bytespersec;
00454 short bytesperechant;
00455 short bitperchannel;
00456 char data[4];
00457 int datalength;
00458 };
00459
00460 static UCallbackAction sendSound_(void * cb, const UMessage &msg)
00461 {
00462
00463
00464
00465
00466 static const int CHUNK_SIZE = 32 * 8*60;
00467
00468
00469
00470 sendSoundData *s=(sendSoundData *)cb;
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 if (s->format == SOUND_WAV && s->pos==0)
00494 s->pos = sizeof (wavheader);
00495 int tosend = (s->length-s->pos > CHUNK_SIZE) ? CHUNK_SIZE:s->length-s->pos;
00496
00497
00498 int playlength = tosend *1000 / s->bytespersec;
00499 s->uc->send("%s.val = BIN %d %s %s;",
00500 s->device,
00501 (int)(tosend+ ((s->format == SOUND_WAV)?sizeof (wavheader):0)),
00502 (s->format == SOUND_WAV)?"wav":"raw",
00503 s->formatString
00504 );
00505 if (s->format == SOUND_WAV)
00506 {
00507 wavheader wh;
00508 memcpy(&wh, s->buffer, sizeof (wh));
00509 wh.datalength=tosend;
00510 wh.length=tosend+44-8;
00511 s->uc->sendBin(&wh, sizeof (wavheader));
00512 }
00513
00514
00515 #if 0
00516
00517 int msecpause = ((SUBCHUNK_SIZE / 32) * 10) / 14;
00518 int spos = 0;
00519 while (spos != tosend)
00520 {
00521 int ts = SUBCHUNK_SIZE;
00522 if (ts > tosend-spos)
00523 ts = tosend-spos;
00524 printf("%d chunk\n", mtime());
00525 s->uc->sendBin(s->buffer, ts);
00526 s->buffer += ts;
00527 spos += ts;
00528 usleep(msecpause);
00529 }
00530 #endif
00531
00532 s->uc->sendBin(s->buffer+s->pos, tosend);
00533 s->uc->send("wait(%s.remain < %d);"
00534 " %s: ping;", s->device, playlength / 2, msg.tag.c_str());
00535
00536 s->pos += tosend;
00537 if (s->pos >= s->length )
00538 {
00539
00540
00541
00542
00543 s->uc->send("speaker->blend=speaker.sendsoundsaveblend;");
00544 if (s->tag && s->tag[0])
00545 s->uc->send("%s: 1;", s->tag);
00546 free(s->buffer);
00547 free(s->tag);
00548 free(s->device);
00549 delete s;
00550 return URBI_REMOVE;
00551 }
00552 return URBI_CONTINUE;
00553 }
00554
00561 int
00562 UAbstractClient::sendSound(const char* device, const USound& sound,
00563 const char* tag)
00564 {
00565 if (sound.soundFormat == SOUND_MP3)
00566 {
00567
00568 return sendBin(sound.data, sound.size,
00569 "%s +report: %s.val = BIN %d mp3;",
00570 tag, device, sound.size);
00571 }
00572 if (sound.soundFormat == SOUND_OGG)
00573 {
00574
00575 return sendBin(sound.data, sound.size,
00576 "%s +report: %s.val = BIN %d ogg;",
00577 tag, device, sound.size);
00578 }
00579
00580 if (sound.soundFormat == SOUND_WAV
00581 || sound.soundFormat == SOUND_RAW)
00582 {
00583 send("speaker.sendsoundsaveblend = speaker->blend;"
00584 "speaker->blend=queue;");
00585 sendSoundData *s = new sendSoundData();
00586 char utag[16];
00587 makeUniqueTag(utag);
00588 s->bytespersec = sound.channels * sound.rate * (sound.sampleSize / 8);
00589 s->uc = this;
00590 s->buffer = static_cast<char*> (malloc (sound.size));
00591 memcpy(s->buffer, sound.data, sound.size);
00592 s->length = sound.size;
00593 s->tag = tag ? strdup(tag) : 0;
00594 s->device = strdup(device);
00595 s->pos = 0;
00596 s->format = sound.soundFormat;
00597 if (sound.soundFormat == SOUND_RAW)
00598 sprintf(s->formatString, "%d %d %d %d",
00599 sound.channels, sound.rate, sound.sampleSize,
00600 (int) sound.sampleFormat);
00601 else
00602 s->formatString[0] = 0;
00603 s->startNotify = false;
00604 UCallbackID cid=setCallback(sendSound_, s, utag);
00605
00606 if (sendSound_(s, UMessage(*this, 0, utag, "*** stop",
00607 std::list<BinaryData>()))==URBI_CONTINUE)
00608 {
00609 if (sendSound_(s, UMessage(*this, 0, utag, "*** stop",
00610 std::list<BinaryData>()))==URBI_REMOVE)
00611 {
00612 deleteCallback(cid);
00613 }
00614 }
00615 else
00616 deleteCallback(cid);
00617 return 0;
00618 }
00619
00620 return 1;
00621 }
00622
00623 UCallbackID
00624 UAbstractClient::setCallback(UCallback cb, const char *tag)
00625 {
00626 return addCallback(tag, *new UCallbackWrapperCB(cb));
00627 }
00628
00629 UCallbackID
00630 UAbstractClient::setCallback(UCustomCallback cb,
00631 void* cbData,
00632 const char* tag)
00633 {
00634 return addCallback(tag, *new UCallbackWrapperCCB(cb, cbData));
00635 }
00636
00639 int
00640 UAbstractClient::getAssociatedTag(UCallbackID id, char * tag)
00641 {
00642 listLock.lock();
00643 std::list<UCallbackInfo>:: iterator it = find(callbackList.begin(),
00644 callbackList.end(), id);
00645 if (it == callbackList.end())
00646 {
00647 listLock.unlock();
00648 return 0;
00649 }
00650 strcpy(tag, it->tag);
00651 listLock.unlock();
00652 return 1;
00653 }
00654
00655
00658 int
00659 UAbstractClient::deleteCallback(UCallbackID callbackID)
00660 {
00661 listLock.lock();
00662 std::list<UCallbackInfo>:: iterator it = find(callbackList.begin(),
00663 callbackList.end(),
00664 callbackID);
00665 if (it == callbackList.end())
00666 {
00667 listLock.unlock();
00668 return 0;
00669 }
00670 delete &(it->callback);
00671 callbackList.erase(it);
00672 listLock.unlock();
00673 return 1;
00674 }
00675
00676 UCallbackID
00677 UAbstractClient::sendCommand(UCallback cb, const char *cmd, ...)
00678 {
00679 char tag[16];
00680 makeUniqueTag(tag);
00681 char *mcmd = new char[strlen(cmd) + strlen(tag) + 5];
00682 sprintf(mcmd, "%s: %s", tag, cmd);
00683 UCallbackID cid = setCallback(cb, tag);
00684 sendBufferLock.lock();
00685 va_list arg;
00686 va_start(arg, cmd);
00687 vpack(mcmd, arg);
00688 va_end(arg);
00689 int retval = effectiveSend(sendBuffer, strlen(sendBuffer));
00690 sendBuffer[0] = 0;
00691 sendBufferLock.unlock();
00692 delete [] mcmd;
00693 if (retval)
00694 {
00695 deleteCallback(cid);
00696 return UINVALIDCALLBACKID;
00697 }
00698 return cid;
00699 }
00700
00701 UCallbackID
00702 UAbstractClient::sendCommand(UCustomCallback cb, void *cbData,
00703 const char *cmd, ...)
00704 {
00705 char tag[16];
00706 makeUniqueTag(tag);
00707 char *mcmd = new char[strlen(cmd) + strlen(tag) + 10];
00708 sprintf(mcmd, "%s: %s", tag, cmd);
00709 UCallbackID cid = setCallback(cb, cbData, tag);
00710 sendBufferLock.lock();
00711 va_list arg;
00712 va_start(arg, cmd);
00713 vpack(mcmd, arg);
00714 va_end(arg);
00715 int retval = effectiveSend(sendBuffer, strlen(sendBuffer));
00716 sendBuffer[0] = 0;
00717 sendBufferLock.unlock();
00718 delete []mcmd;
00719 if (retval)
00720 {
00721 deleteCallback(cid);
00722 return UINVALIDCALLBACKID;
00723 }
00724 return cid;
00725
00726 }
00727
00728 int
00729 UAbstractClient::putFile(const char * localName, const char * remoteName)
00730 {
00731 int len;
00732 struct stat st;
00733 if (stat(localName, &st) == -1)
00734 return 1;
00735 len = st.st_size;
00736 sendBufferLock.lock();
00737 if (!canSend(len + strlen(remoteName) + 20))
00738 {
00739 sendBufferLock.unlock();
00740 return -1;
00741 }
00742
00743 if (!remoteName)
00744 remoteName = localName;
00745 send("save(\"%s\", \"", remoteName);
00746 int res = sendFile(localName);
00747 send("\");");
00748 sendBufferLock.unlock();
00749 return res;
00750 }
00751
00752 int
00753 UAbstractClient::putFile(const void * buffer, int length,
00754 const char * remoteName)
00755 {
00756 if (!canSend(length+strlen(remoteName)+ 20))
00757 {
00758 sendBufferLock.unlock();
00759 return -1;
00760 }
00761 send("save(\"%s\", \"", remoteName);
00762 sendBin(buffer, length);
00763 send("\");");
00764 sendBufferLock.unlock();
00765 return 0;
00766 }
00767
00768 void
00769 UAbstractClient::makeUniqueTag(char* tag)
00770 {
00771 sprintf(tag, "URBI_%d", ++uid);
00772 return;
00773 }
00774
00779 void
00780 UAbstractClient::processRecvBuffer()
00781 {
00782 char* endline;
00783 while (true)
00784 {
00785 if (binaryMode)
00786 {
00787
00788 int len = std::min(recvBufferPosition - endOfHeaderPosition,
00789 binaryBufferLength - binaryBufferPosition);
00790 if (binaryBuffer)
00791 memcpy (static_cast<char*> (binaryBuffer) + binaryBufferPosition,
00792 recvBuffer + endOfHeaderPosition, len);
00793 binaryBufferPosition += len;
00794
00795 if (binaryBufferPosition == binaryBufferLength)
00796 {
00797
00798
00799 BinaryData bd;
00800 bd.size = binaryBufferLength;
00801 bd.data = binaryBuffer;
00802 bins.push_back(bd);
00803 binaryBuffer = 0;
00804
00805 if (nBracket == 0)
00806 {
00807
00808
00809 UMessage msg(*this, currentTimestamp, currentTag, currentCommand,
00810 bins);
00811 notifyCallbacks(msg);
00812
00813
00814 while (!bins.empty())
00815 {
00816 free(bins.front().data);
00817 bins.pop_front();
00818 }
00819
00820 parsePosition = 0;
00821
00822 memmove(recvBuffer,
00823 recvBuffer + endOfHeaderPosition + len,
00824 recvBufferPosition - len - endOfHeaderPosition);
00825 recvBufferPosition = recvBufferPosition - len - endOfHeaderPosition;
00826 }
00827 else
00828 {
00829
00830
00831
00832 memmove(recvBuffer+parsePosition,
00833 recvBuffer + endOfHeaderPosition + len,
00834 recvBufferPosition - len - endOfHeaderPosition);
00835 recvBufferPosition = recvBufferPosition - len;
00836 }
00837 binaryBuffer = 0;
00838 binaryMode = false;
00839
00840
00841 continue;
00842 }
00843 else
00844 {
00845
00846 recvBufferPosition = endOfHeaderPosition;
00847 return;
00848 }
00849 }
00850 else
00851 {
00852
00853 endline = static_cast<char*> (memchr(recvBuffer+parsePosition, '\n',
00854 recvBufferPosition));
00855 if (!endline)
00856 return;
00857
00858 #if 0
00859
00860 printf("ding %15s\n", recvBuffer);
00861 endline2 = static_cast<char*> (memchr(recvBuffer, 0,
00862 recvBufferPosition));
00863 if ((unsigned int) endline - (unsigned int) recvBuffer > 50U)
00864 printf("WARNING, header unexpectedly long\n");
00865 if ((unsigned int) endline > (unsigned int) endline2 && endline2)
00866 printf("WARNING, 0 before newline\n");
00867 #endif
00868
00869
00870 #if DEBUG
00871 printf("%d parse line: --%s--\n", mtime(), recvBuffer);
00872 #endif
00873 if (parsePosition == 0)
00874 {
00875 int found = sscanf(recvBuffer, "[%d:%64[A-Za-z0-9_.]]",
00876 ¤tTimestamp, currentTag);
00877 if (found != 2)
00878 {
00879 found = sscanf(recvBuffer, "[%d]", ¤tTimestamp);
00880 if (found == 1)
00881 currentTag[0] = 0;
00882 else
00883 {
00884 printf("UAbstractClient::read, fatal error parsing header");
00885 printf(" line was '%s'\n", recvBuffer);
00886 currentTimestamp = 0;
00887 strcpy(currentTag, "UNKNWN");
00888
00889 UMessage msg(*this, 0, URBI_ERROR_TAG,
00890 "!!! UAbstractClient::read, fatal error parsing header",
00891 std::list<BinaryData>());
00892 notifyCallbacks(msg);
00893
00894 }
00895 }
00896
00897 currentCommand = strstr(recvBuffer, "]");
00898 if (!currentCommand) {
00899
00900 nBracket = 0;
00901 inString = false;
00902 parsePosition = 0;
00903 recvBufferPosition = 0;
00904 return;
00905 }
00906
00907 ++currentCommand;
00908 while (*currentCommand == ' ')
00909 ++currentCommand;
00910 system = (*currentCommand == '!' || *currentCommand == '*');
00911 parsePosition = (long) currentCommand - (long) recvBuffer;
00912
00913
00914 nBracket = 0;
00915 inString = false;
00916 }
00917
00918 while (parsePosition < recvBufferPosition)
00919 {
00920 if (inString)
00921 {
00922 if (recvBuffer[parsePosition]=='\\')
00923 {
00924 if (parsePosition == recvBufferPosition-1)
00925 {
00926
00927 return;
00928 }
00929 parsePosition+=2;
00930 continue;
00931 }
00932 if (recvBuffer[parsePosition]=='"')
00933 {
00934 inString = false;
00935 ++parsePosition;
00936 continue;
00937 }
00938 }
00939 else
00940 {
00941 if (recvBuffer[parsePosition]=='"')
00942 {
00943 inString = true;
00944 ++parsePosition;
00945 continue;
00946 }
00947 if (recvBuffer[parsePosition]=='[')
00948 {
00949 ++nBracket;
00950 ++parsePosition;
00951 continue;
00952 }
00953 if (recvBuffer[parsePosition]==']')
00954 {
00955 --nBracket;
00956 ++parsePosition;
00957 continue;
00958 }
00959 if (recvBuffer[parsePosition]=='\n')
00960 {
00961 if (true )
00962 {
00963
00964 recvBuffer[parsePosition]=0;
00965
00966 UMessage msg(*this, currentTimestamp, currentTag,
00967 currentCommand,
00968 bins);
00969 notifyCallbacks(msg);
00970
00971
00972 memmove(recvBuffer, recvBuffer + parsePosition + 1,
00973 recvBufferPosition - parsePosition - 1);
00974
00975 recvBufferPosition = recvBufferPosition - parsePosition - 1;
00976 recvBuffer[recvBufferPosition] = 0;
00977 parsePosition = 0;
00978 while (!bins.empty())
00979 {
00980 free(bins.front().data);
00981 bins.pop_front();
00982 }
00983 break;
00984 }
00985
00986 fprintf(stderr, "FATAL PARSE ERROR\n");
00987 }
00988 if (!system && !strncmp(recvBuffer+parsePosition-3, "BIN ", 4))
00989 {
00990
00991
00992 char * endLength;
00993 binaryBufferLength = strtol(recvBuffer+parsePosition+1, &endLength, 0);
00994 if (endLength == recvBuffer+parsePosition+1)
00995 {
00996 printf("UClient::read, error parsing bin data length.\n");
00997 recvBufferPosition = 0;
00998 return;
00999 }
01000
01001 while (recvBuffer[parsePosition] !='\n')
01002 ++parsePosition;
01003 ++parsePosition;
01004 endOfHeaderPosition = parsePosition;
01005 binaryMode = true;
01006 binaryBuffer = malloc(binaryBufferLength);
01007 binaryBufferPosition = 0;
01008 break;
01009 }
01010 }
01011 ++parsePosition;
01012 }
01013
01014 if (parsePosition == recvBufferPosition)
01015 return;
01016 continue;
01017 }
01018 }
01019 }
01020
01021 UCallbackID UAbstractClient::setWildcardCallback(UCallbackWrapper& callback)
01022 {
01023 return addCallback(URBI_WILDCARD_TAG, callback);
01024 }
01025
01026 UCallbackID UAbstractClient::setErrorCallback(UCallbackWrapper& callback)
01027 {
01028 return addCallback(URBI_ERROR_TAG, callback);
01029 }
01030
01031 UCallbackID UAbstractClient::setCallback(UCallbackWrapper& callback,
01032 const char* tag)
01033 {
01034 return addCallback(tag, callback);
01035 }
01036
01037 UCallbackID UAbstractClient::addCallback(const char* tag,
01038 UCallbackWrapper& w)
01039 {
01040 listLock.lock();
01041 UCallbackInfo ci(w);
01042 strncpy(ci.tag, tag, URBI_MAX_TAG_LENGTH-1);
01043 ci.tag[URBI_MAX_TAG_LENGTH-1]=0;
01044 ci.id = ++nextId;
01045 callbackList.push_front(ci);
01046 listLock.unlock();
01047 return ci.id;
01048 }
01049
01050
01051 UMessage::UMessage(UAbstractClient& client, int timestamp,
01052 const char *tag, const char *message,
01053 std::list<BinaryData> bins)
01054 : client(client), timestamp(timestamp), tag(tag), value(0)
01055 {
01056 rawMessage = std::string(message);
01057 while (message[0] ==' ')
01058 ++message;
01059
01060 if (message[0] == '*')
01061 {
01062
01063 type = MESSAGE_SYSTEM;
01064 this->message = (std::string)(message+3);
01065 return;
01066 }
01067
01068 if (message[0] == '!')
01069 {
01070
01071 type = MESSAGE_ERROR;
01072 this->message = (std::string)(message+3);
01073 return;
01074 }
01075
01076
01077 type = MESSAGE_DATA;
01078 value = new UValue();
01079 std::list<BinaryData>::iterator iter = bins.begin();
01080 int p = value->parse(message, 0, bins, iter);
01081 while (message[p] == ' ')
01082 ++p;
01083
01084
01085 if (p < 0 || iter != bins.end())
01086 {
01087 std::cerr << "PARSE ERROR in " << message << "at " << abs(p) << std::endl;
01088 }
01089 }
01090
01091 UMessage::UMessage(const UMessage& b)
01092 : client(b.client)
01093 {
01094 rawMessage = b.rawMessage;
01095 timestamp = b.timestamp;
01096 tag = b.tag;
01097 type = b.type;
01098 value = 0;
01099 switch (type)
01100 {
01101 case MESSAGE_SYSTEM:
01102 case MESSAGE_ERROR:
01103 message = b.message;
01104 break;
01105 default:
01106 value = new UValue(*b.value);
01107 break;
01108 }
01109 }
01110
01111
01112 UMessage::~UMessage()
01113 {
01114 if (type != MESSAGE_SYSTEM && type != MESSAGE_ERROR && value)
01115 delete value;
01116 }
01117
01118 std::ostream& operator <<(std::ostream &s, const UMessage &m)
01119 {
01120 s<<"["<<m.timestamp<<":"<<m.tag<<"] ";
01121 switch (m.type)
01122 {
01123 case MESSAGE_SYSTEM:
01124 case MESSAGE_ERROR:
01125 s<<m.message;
01126 break;
01127 default:
01128 s<<*m.value;
01129 break;
01130 }
01131 return s;
01132 }
01133
01134 UClient * defaultClient=0;
01135
01136 UClient * getDefaultClient()
01137 {
01138 return defaultClient;
01139 }
01140
01141 void setDefaultClient(UClient * cl)
01142 {
01143 defaultClient = cl;
01144 }
01145
01146 std::ostream& unarmorAndSend(const char * a)
01147 {
01148 std::ostream& s =
01149 (getDefaultClient()==0
01150 ? std::cerr
01151 : ((UAbstractClient*)getDefaultClient())->getStream());
01152 if (strlen(a)>2)
01153 if (a[0]=='(' && a[strlen(a)-1]==')')
01154 s.rdbuf()->sputn(a+1, strlen(a)-2);
01155 else
01156 s << a;
01157 return s;
01158 }
01159
01160 }