diff options
| author | Felix Domke <tmbinc@elitedvb.net> | 2003-10-17 15:36:42 +0000 |
|---|---|---|
| committer | Felix Domke <tmbinc@elitedvb.net> | 2003-10-17 15:36:42 +0000 |
| commit | d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5 (patch) | |
| tree | 84d0cacfd0b6c1241c236c7860f7cbd7f26901bb /lib/base | |
| download | enigma2-d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5.tar.gz enigma2-d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5.zip | |
import of enigma2
Diffstat (limited to 'lib/base')
33 files changed, 5563 insertions, 0 deletions
diff --git a/lib/base/Makefile.am b/lib/base/Makefile.am new file mode 100644 index 00000000..3e695a39 --- /dev/null +++ b/lib/base/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = \ + -I$(top_srcdir)/include + +noinst_LIBRARIES = libenigma_base.a + +libenigma_base_a_SOURCES = \ + buffer.cpp console.cpp ebase.cpp econfig.cpp eerror.cpp elock.cpp \ + estring.cpp init.cpp message.cpp nconfig.cpp nxml.cpp thread.cpp \ + smartptr.cpp diff --git a/lib/base/Makefile.in b/lib/base/Makefile.in new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/lib/base/Makefile.in diff --git a/lib/base/a b/lib/base/a new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/lib/base/a diff --git a/lib/base/buffer.cpp b/lib/base/buffer.cpp new file mode 100644 index 00000000..07e9d7f1 --- /dev/null +++ b/lib/base/buffer.cpp @@ -0,0 +1,196 @@ +#include <lib/base/buffer.h> +#include <lib/base/eerror.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> + +void eIOBuffer::removeblock() +{ + ASSERT(!buffer.empty()); + eIOBufferData &b=buffer.front(); + delete[] b.data; + buffer.pop_front(); + ptr=0; +} + +eIOBuffer::eIOBufferData &eIOBuffer::addblock() +{ + eIOBufferData s; + s.data=new __u8[allocationsize]; + s.len=0; + buffer.push_back(s); + return buffer.back(); +} + +eIOBuffer::~eIOBuffer() +{ + clear(); +} + +void eIOBuffer::clear() +{ + while (!buffer.empty()) + removeblock(); +} + +int eIOBuffer::size() const +{ + int total=0; + for (std::list<eIOBufferData>::const_iterator i(buffer.begin()); i != buffer.end(); ++i) + total+=i->len; + total-=ptr; + return total; +} + +int eIOBuffer::empty() const +{ + return buffer.empty(); +} + +int eIOBuffer::peek(void *dest, int len) const +{ + __u8 *dst=(__u8*)dest; + std::list<eIOBufferData>::const_iterator i(buffer.begin()); + int p=ptr; + int written=0; + while (len) + { + if (i == buffer.end()) + break; + int tc=i->len-p; + if (tc > len) + tc = len; + + memcpy(dst, i->data+p, tc); + dst+=tc; + written+=tc; + + ++i; + p=0; + + len-=tc; + } + return written; +} + +void eIOBuffer::skip(int len) +{ + while (len) + { + ASSERT(! buffer.empty()); + int tn=len; + if (tn > (buffer.front().len-ptr)) + tn=buffer.front().len-ptr; + + ptr+=tn; + if (ptr == buffer.front().len) + removeblock(); + len-=tn; + } +} + +int eIOBuffer::read(void *dest, int len) +{ + __u8 *dst=(__u8*)dest; + len=peek(dst, len); + skip(len); + return len; +} + +void eIOBuffer::write(const void *source, int len) +{ + const __u8 *src=(const __u8*)source; + while (len) + { + int tc=len; + if (buffer.empty() || (allocationsize == buffer.back().len)) + addblock(); + if (tc > allocationsize-buffer.back().len) + tc=allocationsize-buffer.back().len; + memcpy(buffer.back().data+buffer.back().len, src, tc); + src+=tc; + buffer.back().len+=tc; + len-=tc; + } +} + +int eIOBuffer::fromfile(int fd, int len) +{ + int re=0; + while (len) + { + int tc=len; + int r; + if (buffer.empty() || (allocationsize == buffer.back().len)) + addblock(); + if (tc > allocationsize-buffer.back().len) + tc=allocationsize-buffer.back().len; + r=::read(fd, buffer.back().data+buffer.back().len, tc); + buffer.back().len+=r; + len-=r; + if (r < 0) + { + if (errno != EWOULDBLOCK) + eDebug("read: %m"); + r=0; + } + re+=r; + if (r != tc) + break; + } + return re; +} + +int eIOBuffer::tofile(int fd, int len) +{ + int written=0; + int w; + while (len && !buffer.empty()) + { + if (buffer.begin() == buffer.end()) + break; + int tc=buffer.front().len-ptr; + if (tc > len) + tc = len; + + w=::write(fd, buffer.front().data+ptr, tc); + if (w < 0) + { + if (errno != EWOULDBLOCK) + eDebug("write: %m"); + w=0; + } + ptr+=w; + if (ptr == buffer.front().len) + removeblock(); + written+=w; + + len-=w; + if (tc != w) + break; + } + return written; +} + +int eIOBuffer::searchchr(char ch) const +{ + std::list<eIOBufferData>::const_iterator i(buffer.begin()); + int p=ptr; + int c=0; + while (1) + { + if (i == buffer.end()) + break; + while (p < i->len) + { + if (i->data[p] == ch) + return c; + else + c++, p++; + } + ++i; + p=0; + } + return -1; +} + diff --git a/lib/base/buffer.h b/lib/base/buffer.h new file mode 100644 index 00000000..9108ba8b --- /dev/null +++ b/lib/base/buffer.h @@ -0,0 +1,40 @@ +#ifndef __src_lib_base_buffer_h +#define __src_lib_base_buffer_h + +#include <asm/types.h> +#include <list> + +/** + * IO buffer. + */ +class eIOBuffer +{ + int allocationsize; + struct eIOBufferData + { + __u8 *data; + int len; + }; + std::list<eIOBufferData> buffer; + void removeblock(); + eIOBufferData &addblock(); + int ptr; +public: + eIOBuffer(int allocationsize): allocationsize(allocationsize), ptr(0) + { + } + ~eIOBuffer(); + int size() const; + int empty() const; + void clear(); + int peek(void *dest, int len) const; + void skip(int len); + int read(void *dest, int len); + void write(const void *source, int len); + int fromfile(int fd, int len); + int tofile(int fd, int len); + + int searchchr(char ch) const; +}; + +#endif diff --git a/lib/base/console.cpp b/lib/base/console.cpp new file mode 100644 index 00000000..2609582f --- /dev/null +++ b/lib/base/console.cpp @@ -0,0 +1,248 @@ +/* + * console.cpp + * + * Copyright (C) 2002 Felix Domke <tmbinc@tuxbox.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: console.cpp,v 1.1 2003-10-17 15:35:47 tmbinc Exp $ + */ + +#include <lib/base/console.h> + +#include <lib/base/estring.h> +#include <sys/vfs.h> // for statfs +#include <unistd.h> +#include <signal.h> +#include <errno.h> + +int bidirpipe(int pfd[], char *cmd , char *argv[]) +{ + int pfdin[2]; /* from child to parent */ + int pfdout[2]; /* from parent to child */ + int pfderr[2]; /* stderr from child to parent */ + int pid; /* child's pid */ + + if ( pipe(pfdin) == -1 || pipe(pfdout) == -1 || pipe(pfderr) == -1) + return(-1); + + if ( ( pid = fork() ) == -1 ) + return(-1); + else if (pid == 0) /* child process */ + { + if ( close(0) == -1 || close(1) == -1 || close(2) == -1 ) + _exit(0); + + if (dup(pfdout[0]) != 0 || dup(pfdin[1]) != 1 || dup(pfderr[1]) != 2 ) + _exit(0); + + if (close(pfdout[0]) == -1 || close(pfdout[1]) == -1 || + close(pfdin[0]) == -1 || close(pfdin[1]) == -1 || + close(pfderr[0]) == -1 || close(pfderr[1]) == -1 ) + _exit(0); + + execv(cmd,argv); + _exit(0); + } + if (close(pfdout[0]) == -1 || close(pfdin[1]) == -1 || close(pfderr[1]) == -1) + return(-1); + + pfd[0] = pfdin[0]; + pfd[1] = pfdout[1]; + pfd[2] = pfderr[0]; + + return(pid); +} + +eConsoleAppContainer::eConsoleAppContainer( const eString &cmd ) +:pid(-1), killstate(0), outbuf(0) +{ +// eDebug("cmd = %s", cmd.c_str() ); + memset(fd, 0, sizeof(fd) ); + int cnt=2; // path to app + terminated 0 + eString str(cmd?cmd:""); + + while( str.length() && str[0] == ' ' ) // kill spaces at beginning + str = str.mid(1); + + while( str.length() && str[str.length()-1] == ' ' ) // kill spaces at the end + str = str.left( str.length() - 1 ); + + if (!str.length()) + return; + + unsigned int idx=0; + eString path = str.left( (idx = str.find(' ')) != eString::npos ? idx : str.length() ); +// eDebug("path = %s", path.c_str() ); + + eString cmds = str.mid( path.length()+1 ); +// eDebug("cmds = %s", cmds.c_str() ); + + idx = 0; + while ( (idx = cmds.find(' ',idx) ) != eString::npos ) // count args + { + cnt++; + idx++; + } + +// eDebug("idx = %d, %d counted spaces", idx, cnt-2); + + if ( cmds.length() ) + { + cnt++; +// eDebug("increase cnt"); + } + +// eDebug("%d args", cnt-2); + char **argv = new char*[cnt]; // min two args... path and terminating 0 + argv[0] = new char[ path.length() ]; + strcpy( argv[0], path.c_str() ); + argv[cnt-1] = 0; // set terminating null + + if ( cnt > 2 ) // more then default args? + { + cnt=1; // do not overwrite path in argv[0] + + while ( (idx = cmds.find(' ')) != eString::npos ) // parse all args.. + { + argv[cnt] = new char[ idx ]; +// eDebug("idx=%d, arg = %s", idx, cmds.left(idx).c_str() ); + strcpy( argv[cnt++], cmds.left( idx ).c_str() ); + cmds = cmds.mid(idx+1); +// eDebug("str = %s", cmds.c_str() ); + } + // store the last arg + argv[cnt] = new char[ cmds.length() ]; + strcpy( argv[cnt], cmds.c_str() ); + } + + // get one read ,one write and the err pipe to the prog.. + + if ( (pid = bidirpipe(fd, argv[0], argv)) == -1 ) + { + while ( cnt-- > 0 ) + delete [] argv[cnt]; + delete [] argv; + return; + } + + while ( cnt-- > 0 ) // release heap memory + delete [] argv[cnt]; + delete [] argv; + + eDebug("pipe in = %d, out = %d, err = %d", fd[0], fd[1], fd[2]); + + in = new eSocketNotifier(eApp, fd[0], 19 ); // 19 = POLLIN, POLLPRI, POLLHUP + out = new eSocketNotifier(eApp, fd[1], eSocketNotifier::Write); // POLLOUT + err = new eSocketNotifier(eApp, fd[2], 19 ); // 19 = POLLIN, POLLPRI, POLLHUP + CONNECT(in->activated, eConsoleAppContainer::readyRead); + CONNECT(out->activated, eConsoleAppContainer::readyWrite); + CONNECT(err->activated, eConsoleAppContainer::readyErrRead); + signal(SIGCHLD, SIG_IGN); // no zombie when child killed +} + +eConsoleAppContainer::~eConsoleAppContainer() +{ + if ( running() ) + { + killstate=-1; + kill(); + } + if ( outbuf ) + delete [] outbuf; +} + +void eConsoleAppContainer::kill() +{ + killstate=-1; + system( eString().sprintf("kill %d", pid).c_str() ); + eDebug("user kill console App"); +} + +void eConsoleAppContainer::closePipes() +{ + in->stop(); + out->stop(); + err->stop(); + ::close(fd[0]); + fd[0]=0; + ::close(fd[1]); + fd[1]=0; + ::close(fd[2]); + fd[2]=0; + eDebug("pipes closed"); +} + +void eConsoleAppContainer::readyRead(int what) +{ + if (what & POLLPRI|POLLIN) + { + eDebug("what = %d"); + char buf[2048]; + int readed = read(fd[0], buf, 2048); + eDebug("%d bytes read", readed); + if ( readed != -1 && readed ) + /*emit*/ dataAvail( eString( buf ) ); + else if (readed == -1) + eDebug("readerror %d", errno); + } + if (what & eSocketNotifier::Hungup) + { + eDebug("child has terminated"); + closePipes(); + /*emit*/ appClosed(killstate); + } +} + +void eConsoleAppContainer::readyErrRead(int what) +{ + if (what & POLLPRI|POLLIN) + { + eDebug("what = %d"); + char buf[2048]; + int readed = read(fd[2], buf, 2048); + eDebug("%d bytes read", readed); + if ( readed != -1 && readed ) + /*emit*/ dataAvail( eString( buf ) ); + else if (readed == -1) + eDebug("readerror %d", errno); + } +} + +void eConsoleAppContainer::write( const eString & str ) +{ + outbuf = new char[ str.length()]; + strcpy( outbuf, str.c_str() ); +} + +void eConsoleAppContainer::readyWrite(int what) +{ + if (what == 4 && outbuf) + { + if ( ::write( fd[1], outbuf, strlen(outbuf) ) != (int) strlen(outbuf) ) + { + /* emit */ dataSent(-1); + eDebug("writeError"); + } + else + { + /* emit */ dataSent(0); + eDebug("write ok"); + } + + delete outbuf; + outbuf=0; + } +} diff --git a/lib/base/console.h b/lib/base/console.h new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/lib/base/console.h diff --git a/lib/base/ebase.cpp b/lib/base/ebase.cpp new file mode 100644 index 00000000..3babc2eb --- /dev/null +++ b/lib/base/ebase.cpp @@ -0,0 +1,206 @@ +#include <lib/base/ebase.h> + +#include <fcntl.h> +#include <unistd.h> + +#include <lib/base/eerror.h> + +eSocketNotifier::eSocketNotifier(eMainloop *context, int fd, int requested, bool startnow): context(*context), fd(fd), state(0), requested(requested) +{ + if (startnow) + start(); +} + +eSocketNotifier::~eSocketNotifier() +{ + stop(); +} + +void eSocketNotifier::start() +{ + if (state) + stop(); + + context.addSocketNotifier(this); + state=1; +} + +void eSocketNotifier::stop() +{ + if (state) + context.removeSocketNotifier(this); + + state=0; +} + + // timer +void eTimer::start(long msek, bool singleShot) +{ + if (bActive) + stop(); + + bActive = true; + bSingleShot = singleShot; + interval = msek; + gettimeofday(&nextActivation, 0); +// eDebug("this = %p\nnow sec = %d, usec = %d\nadd %d msec", this, nextActivation.tv_sec, nextActivation.tv_usec, msek); + nextActivation += (msek<0 ? 0 : msek); +// eDebug("next Activation sec = %d, usec = %d", nextActivation.tv_sec, nextActivation.tv_usec ); + context.addTimer(this); +} + +void eTimer::stop() +{ + if (bActive) + { + bActive=false; + context.removeTimer(this); + } +} + +void eTimer::changeInterval(long msek) +{ + if (bActive) // Timer is running? + { + context.removeTimer(this); // then stop + nextActivation -= interval; // sub old interval + } + else + bActive=true; // then activate Timer + + interval = msek; // set new Interval + nextActivation += interval; // calc nextActivation + + context.addTimer(this); // add Timer to context TimerList +} + +void eTimer::activate() // Internal Funktion... called from eApplication +{ + timeval now; + gettimeofday(&now, 0); +// eDebug("this = %p\nnow sec = %d, usec = %d\nnextActivation sec = %d, usec = %d", this, now.tv_sec, now.tv_usec, nextActivation.tv_sec, nextActivation.tv_usec ); +// eDebug("Timer emitted"); + context.removeTimer(this); + + if (!bSingleShot) + { + nextActivation += interval; + context.addTimer(this); + } + else + bActive=false; + + /*emit*/ timeout(); +} + +// mainloop + +void eMainloop::addSocketNotifier(eSocketNotifier *sn) +{ + notifiers.insert(std::pair<int,eSocketNotifier*> (sn->getFD(), sn)); +} + +void eMainloop::removeSocketNotifier(eSocketNotifier *sn) +{ + notifiers.erase(sn->getFD()); +} + +void eMainloop::processOneEvent() +{ +// process pending timers... + long usec=0; + + while (TimerList && (usec = timeout_usec( TimerList.begin()->getNextActivation() ) ) <= 0 ) + TimerList.begin()->activate(); + + int fdAnz = notifiers.size(); + pollfd* pfd = new pollfd[fdAnz]; // make new pollfd array + +// fill pfd array + std::map<int,eSocketNotifier*>::iterator it(notifiers.begin()); + for (int i=0; i < fdAnz; i++, it++) + { + pfd[i].fd = it->first; + pfd[i].events = it->second->getRequested(); + } + + int ret=poll(pfd, fdAnz, TimerList ? usec / 1000 : -1); // milli .. not micro seks + + if (ret>0) + { +// eDebug("bin aussem poll raus und da war was"); + for (int i=0; i < fdAnz ; i++) + { + if( notifiers.find(pfd[i].fd) == notifiers.end()) + continue; + + int req = notifiers[pfd[i].fd]->getRequested(); + + if ( pfd[i].revents & req ) + { + notifiers[pfd[i].fd]->activate(pfd[i].revents); + + if (!--ret) + break; + } else if (pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) + eDebug("poll: unhandled POLLERR/HUP/NVAL for fd %d(%d)", pfd[i].fd,pfd[i].revents); + } + } + else if (ret<0) + eDebug("poll made error"); + + // check Timers... + while ( TimerList && timeout_usec( TimerList.begin()->getNextActivation() ) <= 0 ) + TimerList.begin()->activate(); + + delete [] pfd; +} + + +int eMainloop::exec() +{ + if (!loop_level) + { + app_quit_now = false; + enter_loop(); + } + return retval; +} + +void eMainloop::enter_loop() +{ + loop_level++; + + // Status der vorhandenen Loop merken + bool old_exit_loop = app_exit_loop; + + app_exit_loop = false; + + while (!app_exit_loop && !app_quit_now) + { + processOneEvent(); + } + + // wiederherstellen der vorherigen app_exit_loop + app_exit_loop = old_exit_loop; + + loop_level--; + + if (!loop_level) + { + // do something here on exit the last loop + } +} + +void eMainloop::exit_loop() // call this to leave the current loop +{ + app_exit_loop = true; +} + +void eMainloop::quit( int ret ) // call this to leave all loops +{ + retval=ret; + app_quit_now = true; +} + +eApplication* eApp = 0; diff --git a/lib/base/ebase.h b/lib/base/ebase.h new file mode 100644 index 00000000..b929cb6d --- /dev/null +++ b/lib/base/ebase.h @@ -0,0 +1,252 @@ +#ifndef __ebase_h +#define __ebase_h + +#include <vector> +#include <map> +#include <sys/poll.h> +#include <sys/time.h> +#include <asm/types.h> +#include <time.h> + +#include <lib/base/eptrlist.h> +#include <libsig_comp.h> + +class eApplication; + +extern eApplication* eApp; + +static inline bool operator<( const timeval &t1, const timeval &t2 ) +{ + return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec); +} + +static inline timeval &operator+=( timeval &t1, const timeval &t2 ) +{ + t1.tv_sec += t2.tv_sec; + if ( (t1.tv_usec += t2.tv_usec) >= 1000000 ) + { + t1.tv_sec++; + t1.tv_usec -= 1000000; + } + return t1; +} + +static inline timeval operator+( const timeval &t1, const timeval &t2 ) +{ + timeval tmp; + tmp.tv_sec = t1.tv_sec + t2.tv_sec; + if ( (tmp.tv_usec = t1.tv_usec + t2.tv_usec) >= 1000000 ) + { + tmp.tv_sec++; + tmp.tv_usec -= 1000000; + } + return tmp; +} + +static inline timeval operator-( const timeval &t1, const timeval &t2 ) +{ + timeval tmp; + tmp.tv_sec = t1.tv_sec - t2.tv_sec; + if ( (tmp.tv_usec = t1.tv_usec - t2.tv_usec) < 0 ) + { + tmp.tv_sec--; + tmp.tv_usec += 1000000; + } + return tmp; +} + +static inline timeval operator-=( timeval &t1, const timeval &t2 ) +{ + t1.tv_sec -= t2.tv_sec; + if ( (t1.tv_usec -= t2.tv_usec) < 0 ) + { + t1.tv_sec--; + t1.tv_usec += 1000000; + } + return t1; +} + +static inline timeval &operator+=( timeval &t1, const long msek ) +{ + t1.tv_sec += msek / 1000; + if ( (t1.tv_usec += (msek % 1000) * 1000) >= 1000000 ) + { + t1.tv_sec++; + t1.tv_usec -= 1000000; + } + return t1; +} + +static inline timeval operator+( const timeval &t1, const long msek ) +{ + timeval tmp; + tmp.tv_sec = t1.tv_sec + msek / 1000; + if ( (tmp.tv_usec = t1.tv_usec + (msek % 1000) * 1000) >= 1000000 ) + { + tmp.tv_sec++; + tmp.tv_usec -= 1000000; + } + return tmp; +} + +static inline timeval operator-( const timeval &t1, const long msek ) +{ + timeval tmp; + tmp.tv_sec = t1.tv_sec - msek / 1000; + if ( (tmp.tv_usec = t1.tv_usec - (msek % 1000)*1000) < 0 ) + { + tmp.tv_sec--; + tmp.tv_usec += 1000000; + } + return tmp; +} + +static inline timeval operator-=( timeval &t1, const long msek ) +{ + t1.tv_sec -= msek / 1000; + if ( (t1.tv_usec -= (msek % 1000) * 1000) < 0 ) + { + t1.tv_sec--; + t1.tv_usec += 1000000; + } + return t1; +} + +static inline timeval timeout_timeval ( const timeval & orig ) +{ + timeval now; + gettimeofday(&now,0); + + return orig-now; +} + +static inline long timeout_usec ( const timeval & orig ) +{ + timeval now; + gettimeofday(&now,0); + + return (orig-now).tv_sec*1000000 + (orig-now).tv_usec; +} + +class eMainloop; + + // die beiden signalquellen: SocketNotifier... + +/** + * \brief Gives a callback when data on a file descriptor is ready. + * + * This class emits the signal \c eSocketNotifier::activate whenever the + * event specified by \c req is available. + */ +class eSocketNotifier +{ +public: + enum { Read=POLLIN, Write=POLLOUT, Priority=POLLPRI, Error=POLLERR, Hungup=POLLHUP }; +private: + eMainloop &context; + int fd; + int state; + int requested; // requested events (POLLIN, ...) +public: + /** + * \brief Constructs a eSocketNotifier. + * \param context The thread where to bind the socketnotifier to. The signal is emitted from that thread. + * \param fd The filedescriptor to monitor. Can be a device or a socket. + * \param req The events to watch to, normally either \c Read or \c Write. You can specify any events that \c poll supports. + * \param startnow Specifies if the socketnotifier should start immediately. + */ + eSocketNotifier(eMainloop *context, int fd, int req, bool startnow=true); + ~eSocketNotifier(); + + Signal1<void, int> activated; + void activate(int what) { /*emit*/ activated(what); } + + void start(); + void stop(); + bool isRunning() { return state; } + + int getFD() { return fd; } + int getRequested() { return requested; } + void setRequested(int req) { requested=req; } +}; + + // ... und Timer +/** + * \brief Gives a callback after a specified timeout. + * + * This class emits the signal \c eTimer::timeout after the specified timeout. + */ +class eTimer +{ + eMainloop &context; + timeval nextActivation; + long interval; + bool bSingleShot; + bool bActive; +public: + /** + * \brief Constructs a timer. + * + * The timer is not yet active, it has to be started with \c start. + * \param context The thread from which the signal should be emitted. + */ + eTimer(eMainloop *context): context(*context), bActive(false) { } + ~eTimer() { if (bActive) stop(); } + + Signal0<void> timeout; + void activate(); + + bool isActive() { return bActive; } + timeval &getNextActivation() { return nextActivation; } + + void start(long msec, bool singleShot=false); + void stop(); + void changeInterval(long msek); + bool operator<(const eTimer& t) const { return nextActivation < t.nextActivation; } +}; + + // werden in einer mainloop verarbeitet +class eMainloop +{ + std::map<int, eSocketNotifier*> notifiers; + ePtrList<eTimer> TimerList; + bool app_exit_loop; + bool app_quit_now; + int loop_level; + void processOneEvent(); + int retval; +public: + eMainloop():app_quit_now(0),loop_level(0),retval(0){ } + void addSocketNotifier(eSocketNotifier *sn); + void removeSocketNotifier(eSocketNotifier *sn); + void addTimer(eTimer* e) { TimerList.push_back(e); TimerList.sort(); } + void removeTimer(eTimer* e) { TimerList.remove(e); } + + int looplevel() { return loop_level; } + + int exec(); // recursive enter the loop + void quit(int ret=0); // leave all pending loops (recursive leave()) + void enter_loop(); + void exit_loop(); +}; + +/** + * \brief The application class. + * + * An application provides a mainloop, and runs in the primary thread. + * You can have other threads, too, but this is the primary one. + */ +class eApplication: public eMainloop +{ +public: + eApplication() + { + if (!eApp) + eApp = this; + } + ~eApplication() + { + eApp = 0; + } +}; +#endif diff --git a/lib/base/econfig.cpp b/lib/base/econfig.cpp new file mode 100644 index 00000000..3d51255b --- /dev/null +++ b/lib/base/econfig.cpp @@ -0,0 +1,43 @@ +#include <lib/base/eerror.h> +#include <lib/base/econfig.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> +#include <sys/stat.h> + +eConfig *eConfig::instance; + +eConfig::eConfig() +{ + if (!instance) + instance=this; + + setName(CONFIGDIR "/enigma/registry"); + int e=open(); + if (e == NC_ERR_CORRUPT) + { + eWarning("CORRUTPED REGISTRY!"); + ::remove(CONFIGDIR "/enigma/registry"); + } + if (e) + { + if (createNew()) + { + mkdir(CONFIGDIR "/enigma", 0777); + if (createNew()) + eFatal("error while opening/creating registry - create " CONFIGDIR "/enigma"); + } + if (open()) + eFatal("still can't open configfile"); + } + locked=1; + ppin=0; + getKey("/elitedvb/pins/parentallock", ppin ); +} + +eConfig::~eConfig() +{ + if (instance==this) + instance=0; +} + +eAutoInitP0<eConfig> init_eRCConfig(eAutoInitNumbers::configuration, "Configuration"); diff --git a/lib/base/econfig.h b/lib/base/econfig.h new file mode 100644 index 00000000..d9f3becd --- /dev/null +++ b/lib/base/econfig.h @@ -0,0 +1,27 @@ +#ifndef __econfig_h +#define __econfig_h + +#include <lib/base/nconfig.h> + +class eConfig: public NConfig +{ + static eConfig *instance; + int ppin; +public: + int locked; + static eConfig *getInstance() { return instance; } + void setParentalPin( int pin ) + { + ppin = pin; + setKey("/elitedvb/pins/parentallock", ppin ); + } + int getParentalPin() { return ppin; } + bool pLockActive() + { + return ppin && locked; + } + eConfig(); + ~eConfig(); +}; + +#endif diff --git a/lib/base/eerror.cpp b/lib/base/eerror.cpp new file mode 100644 index 00000000..0871bb71 --- /dev/null +++ b/lib/base/eerror.cpp @@ -0,0 +1,69 @@ +#include <lib/base/eerror.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <lib/gui/emessage.h> + +int infatal=0; + +Signal2<void, int, const eString&> logOutput; +int logOutputConsole=1; + +void eFatal(const char* fmt, ...) +{ + char buf[1024]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, 1024, fmt, ap); + va_end(ap); + logOutput(lvlFatal, buf); + fprintf(stderr, "%s\n",buf ); + if (!infatal) + { + infatal=1; + eMessageBox msg(buf, "FATAL ERROR", eMessageBox::iconError|eMessageBox::btOK); + msg.show(); + msg.exec(); + } + _exit(0); +} + +#ifdef DEBUG +void eDebug(const char* fmt, ...) +{ + char buf[1024]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, 1024, fmt, ap); + va_end(ap); + logOutput(lvlDebug, eString(buf) + "\n"); + if (logOutputConsole) + fprintf(stderr, "%s\n", buf); +} + +void eDebugNoNewLine(const char* fmt, ...) +{ + char buf[1024]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, 1024, fmt, ap); + va_end(ap); + logOutput(lvlDebug, buf); + if (logOutputConsole) + fprintf(stderr, "%s", buf); +} + +void eWarning(const char* fmt, ...) +{ + char buf[1024]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, 1024, fmt, ap); + va_end(ap); + logOutput(lvlWarning, eString(buf) + "\n"); + if (logOutputConsole) + fprintf(stderr, "%s\n", buf); +} +#endif // DEBUG diff --git a/lib/base/eerror.h b/lib/base/eerror.h new file mode 100644 index 00000000..bf913959 --- /dev/null +++ b/lib/base/eerror.h @@ -0,0 +1,43 @@ +#ifndef __E_ERROR__ +#define __E_ERROR__ + +#include "config.h" +#include <string> +#include <map> +#include <new> +#include <libsig_comp.h> + +void eFatal(const char* fmt, ...); + +class eString; + +enum { lvlDebug=1, lvlWarning=2, lvlFatal=4 }; + +extern Signal2<void, int, const eString&> logOutput; +extern int logOutputConsole; + +#ifdef ASSERT +#undef ASSERT +#endif + +#ifdef DEBUG + void eDebug(const char* fmt, ...); + void eDebugNoNewLine(const char* fmt, ...); + void eWarning(const char* fmt, ...); + #define ASSERT(x) { if (!(x)) eFatal("%s:%d ASSERTION %s FAILED!", __FILE__, __LINE__, #x); } +#else + inline void eDebug(const char* fmt, ...) + { + } + + inline void eDebugNoNewLine(const char* fmt, ...) + { + } + + inline void eWarning(const char* fmt, ...) + { + } + #define ASSERT(x) do { } while (0) +#endif //DEBUG + +#endif // __E_ERROR__ diff --git a/lib/base/elock.cpp b/lib/base/elock.cpp new file mode 100644 index 00000000..afddcc6f --- /dev/null +++ b/lib/base/elock.cpp @@ -0,0 +1,104 @@ +#include <lib/base/elock.h> +#include <unistd.h> + +void eLock::lock(int res) +{ + if (res>max) + res=max; + pthread_mutex_lock(&mutex); + while ((counter+res)>max) + pthread_cond_wait(&cond, &mutex); + counter+=res; + pthread_mutex_unlock(&mutex); +} + +void eLock::unlock(int res) +{ + if (res>max) + res=max; + pthread_mutex_lock(&mutex); + counter-=res; + pthread_mutex_unlock(&mutex); + pthread_cond_signal(&cond); +} + +eLock::eLock(int max): max(max) +{ + pthread_mutex_init(&mutex, 0); + pthread_cond_init(&cond, 0); + counter=0; + pid=-1; +} + +eLock::~eLock() +{ + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&cond); +} + +eLocker::eLocker(eLock &lock, int res): lock(lock), res(res) +{ + lock.lock(res); +} + +eLocker::~eLocker() +{ + lock.unlock(res); +} + +eSemaphore::eSemaphore() +{ + v=1; + pthread_mutex_init(&mutex, 0); + pthread_cond_init(&cond, 0); +} + +eSemaphore::~eSemaphore() +{ + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&cond); +} + +int eSemaphore::down() +{ + int value_after_op; + pthread_mutex_lock(&mutex); + while (v<=0) + pthread_cond_wait(&cond, &mutex); + v--; + value_after_op=v; + pthread_mutex_unlock(&mutex); + return value_after_op; +} + +int eSemaphore::decrement() +{ + int value_after_op; + pthread_mutex_lock(&mutex); + v--; + value_after_op=v; + pthread_mutex_unlock(&mutex); + pthread_cond_signal(&cond); + return value_after_op; +} + +int eSemaphore::up() +{ + int value_after_op; + pthread_mutex_lock(&mutex); + v++; + value_after_op=v; + pthread_mutex_unlock(&mutex); + pthread_cond_signal(&cond); + return value_after_op; +} + +int eSemaphore::value() +{ + int value_after_op; + pthread_mutex_lock(&mutex); + value_after_op=v; + pthread_mutex_unlock(&mutex); + return value_after_op; +} + diff --git a/lib/base/elock.h b/lib/base/elock.h new file mode 100644 index 00000000..6a47f8c9 --- /dev/null +++ b/lib/base/elock.h @@ -0,0 +1,60 @@ +#ifndef __elock_h +#define __elock_h + +#include <pthread.h> + +class singleLock +{ + pthread_mutex_t &lock; +public: + singleLock( pthread_mutex_t &m ) + :lock(m) + { + pthread_mutex_lock(&lock); + } + ~singleLock() + { + pthread_mutex_unlock(&lock); + } +}; + +class eLock +{ + pthread_mutex_t mutex; + pthread_cond_t cond; + + int pid; + int counter, max; +public: + void lock(int res=100); + void unlock(int res=100); + + eLock(int max=100); + ~eLock(); +}; + +class eLocker +{ + eLock &lock; + int res; +public: + eLocker(eLock &lock, int res=100); + ~eLocker(); +}; + +class eSemaphore +{ + int v; + pthread_mutex_t mutex; + pthread_cond_t cond; +public: + eSemaphore(); + ~eSemaphore(); + + int down(); + int decrement(); + int up(); + int value(); +}; + +#endif diff --git a/lib/base/eptrlist.h b/lib/base/eptrlist.h new file mode 100644 index 00000000..f1421eb2 --- /dev/null +++ b/lib/base/eptrlist.h @@ -0,0 +1,1338 @@ +#ifndef _E_PTRLIST_ +#define _E_PTRLIST_ + +#include <list> +#include <vector> +#include <lib/base/smartptr.h> + +template <class T> +class ePtrList : public std::list<T*> +{ +public: + typedef typename std::list<T*, std::allocator<T*> >::iterator std_list_T_iterator; // to remove compiler warnings + typedef typename std::list<T*, std::allocator<T*> >::const_iterator std_list_T_const_iterator; + typedef typename std::list<T*, std::allocator<T*> >::reverse_iterator std_list_T_reverse_iterator; + typedef typename std::list<T*, std::allocator<T*> >::const_reverse_iterator std_list_T_const_reverse_iterator; + typedef typename ePtrList<T>::iterator T_iterator; + typedef typename ePtrList<T>::const_iterator T_const_iterator; + typedef typename ePtrList<T>::reverse_iterator T_reverse_iterator; + typedef typename ePtrList<T>::const_reverse_iterator T_const_reverse_iterator; + +// Iterator classes + class iterator; + class const_iterator; + class reverse_iterator; + class const_reverse_iterator; + +// Constructors + inline ePtrList(); + inline ePtrList(const ePtrList&); + inline ~ePtrList(); + +// overwritted sort method + inline void sort(); + +// changed methods for autodelete and current implementation + inline void remove(T* t); + inline void clear(); + inline void pop_back(); + inline void pop_front(); + inline void push_back(T*); + inline void push_front(T*); + +// added methods for current implementation + inline T* take(); + inline void take(T* t); + inline T* current(); + inline T* next(); + inline T* prev(); + inline T* first(); + inline T* last(); + inline T* setCurrent(const T*); + inline const T* current() const; + inline const T* next() const; + inline const T* prev() const; + inline const T* first() const; + inline const T* last() const; + +// added operator methods + inline operator bool(); + inline bool operator!(); + +// added methods for autodelete implementation + inline void setAutoDelete(bool b); + inline bool isAutoDelete(); + +// added compare struct ... to sort + struct less; +private: + iterator cur; + bool autoDelete; + +public: + iterator ePtrList<T>::begin() + { + // makes implicit type conversion form std::list::iterator to ePtrList::iterator + return std::list<T*>::begin(); + } + + iterator ePtrList<T>::end() + { + // makes implicit type conversion form std::list::iterator to ePtrList::iterator + return std::list<T*>::end(); + } + + const_iterator ePtrList<T>::begin() const + { + // makes implicit type conversion form std::list::const_iterator to ePtrList::const_iterator + return std::list<T*>::begin(); + } + + const_iterator ePtrList<T>::end() const + { + // makes implicit type conversion form std::list::const_iterator to ePtrList::const_iterator + return std::list<T*>::end(); + } + + reverse_iterator ePtrList<T>::rbegin() + { + // makes implicit type conversion form std::list::reverse:_iterator to ePtrList::reverse_iterator + return std::list<T*>::rbegin(); + } + + reverse_iterator ePtrList<T>::rend() + { + // makes implicit type conversion form std::list::reverse_iterator to ePtrList::reverse_iterator + return std::list<T*>::rend(); + } + + const_reverse_iterator ePtrList<T>::rbegin() const + { + // makes implicit type conversion form std::list::const_reverse_iterator to ePtrList::const_reverse_iterator + return std::list<T*>::rbegin(); + } + + const_reverse_iterator ePtrList<T>::rend() const + { + // makes implicit type conversion form std::list::const_reverse_iterator to ePtrList::const_reverse_iterator + return std::list<T*>::rend(); + } + + iterator ePtrList<T>::erase(iterator it) + { + // Remove the item it, if auto-deletion is enabled, than the list call delete for this item + // If current is equal to the item that was removed, current is set to the next item in the list + if (autoDelete && *it) + delete *it; + + if (cur == it) + return cur = std::list<T*>::erase(it); + else + return std::list<T*>::erase(it); + } + + iterator ePtrList<T>::erase(iterator from, iterator to) + { + // Remove all items between the to iterators from and to + // If auto-deletion is enabled, than the list call delete for all removed items + while (from != to) + from = erase(from); + + return from; + } + + operator iterator() + { + // Returns a iterator that equal to begin() of the list + return begin(); + } + + operator const_iterator() const + { + // Returns a const_iterator that equal to begin() of the list + return begin(); + } + + operator reverse_iterator() + { + // Returns a reverse_iterator that equal to rbegin() of the list + return rbegin(); + } + + operator const_reverse_iterator() const + { + // Returns a const_reverse_iterator that equal to rbegin() of the list + return rbegin(); + } + + std::vector<T>* getVector() + { + // Creates an vector and copys all elements to this vector + // returns a pointer to this new vector ( the reserved memory must deletet from the receiver !! ) + std::vector<T>* v=new std::vector<T>(); + v->reserve( size() ); + for ( std_list_T_iterator it( std::list<T*>::begin() ); it != std::list<T*>::end(); it++) + v->push_back( **it ); + + return v; + } + + inline iterator insert_in_order( T* e ) + { + // added a new item to the list... in order + // returns a iterator to the new item + return insert( std::lower_bound( std::list<T*>::begin(), std::list<T*>::end(), e ), e ); + } + +}; + +/////////////////// iterator class ///////////////////////////// +template <class T> +class ePtrList<T>::iterator : public std::list<T*>::iterator +{ +public: + // Constructors + iterator(const std_list_T_iterator& Q) : std_list_T_iterator(Q) { } + + // changed operator for pointer + T* operator->() const + { + return *std::list<T*>::iterator::operator->(); + } + + operator T&() const + { + return *operator->(); + } + + operator T*() const + { + return operator->(); + } + + iterator& operator++() + { + std::list<T*>::iterator::operator++(); + return *this; + } + + iterator operator++(int) + { + return std::list<T*>::iterator::operator++(0); + } + + iterator& operator--() + { + std::list<T*>::iterator::operator--(); + return *this; + } + + iterator operator--(int) + { + return std::list<T*>::iterator::operator--(0); + } +}; + +/////////////////// const_iterator class ///////////////////////////// +template <class T> +class ePtrList<T>::const_iterator : public std::list<T*>::const_iterator +{ +public: + // Constructors + const_iterator(const std_list_T_const_iterator& Q) :std_list_T_const_iterator(Q) { } + + // changed operator for pointer + T* operator->() const + { + return *std::list<T*>::const_iterator::operator->(); + } + + operator T&() const + { + return *operator->(); + } + + operator T*() const + { + return operator->(); + } + + const_iterator& operator++() + { + std::list<T*>::const_iterator::operator++(); + return *this; + } + + const_iterator operator++(int) + { + return std::list<T*>::const_iterator::operator++(0); + } + + const_iterator& operator--() + { + std::list<T*>::const_iterator::operator--(); + return *this; + } + + const_iterator operator--(int) + { + return std::list<T*>::const_iterator::operator--(0); + } +}; + +/////////////////// reverse_iterator class ///////////////////////////// +template <class T> +class ePtrList<T>::reverse_iterator : public std::list<T*>::reverse_iterator +{ +public: + // Constructors + reverse_iterator(const std_list_T_reverse_iterator& Q) :std_list_T_reverse_iterator(Q) { } + + // changed operators for pointer + T* operator->() const + { + return *std::list<T*>::reverse_iterator::operator->(); + } + + operator T&() const + { + return *operator->(); + } + + operator T*() const + { + return operator->(); + } + + reverse_iterator& operator++() + { + std::list<T*>::reverse_iterator::operator++(); + return *this; + } + + reverse_iterator operator++(int) + { + return std::list<T*>::reverse_iterator::operator++(0); + } + + reverse_iterator& operator--() + { + std::list<T*>::reverse_iterator::operator--(); + return *this; + } + + reverse_iterator operator--(int) + { + return std::list<T*>::reverse_iterator::operator--(0); + } +}; + +/////////////////// const_reverse_iterator class ///////////////////////////// +template <class T> +class ePtrList<T>::const_reverse_iterator : public std::list<T*>::const_reverse_iterator +{ +public: + // Constructors + const_reverse_iterator(const std_list_T_const_reverse_iterator& Q) :std_list_T_const_reverse_iterator(Q) { } + + // changed operators for pointer + T* operator->() const + { + return *std::list<T*>::const_reverse_iterator::operator->(); + } + + operator T&() const + { + return *operator->(); + } + + operator T*() const + { + return operator->(); + } + + const_reverse_iterator& operator++() + { + std::list<T*>::const_reverse_iterator::operator++(); + return *this; + } + + const_reverse_iterator operator++(int) + { + return std::list<T*>::const_reverse_iterator::operator++(0); + } + + const_reverse_iterator& operator--() + { + std::list<T*>::const_reverse_iterator::operator--(); + return *this; + } + + const_reverse_iterator operator--(int) + { + return std::list<T*>::const_reverse_iterator::operator--(0); + } +}; + +/////////////////// Default Constructor ///////////////////////////// +template <class T> +ePtrList<T>::ePtrList() + :cur(std::list<T*>::begin()), autoDelete(false) +{ + +} + +/////////////////// Copy Constructor ///////////////////////////// +template <class T> +ePtrList<T>::ePtrList(const ePtrList& e) + :std::list<T*>(e), cur(e.cur), autoDelete( false ) +{ + if ( e.autoDelete ) + if ( e.size() ) + eDebug("Warning !! We make a Copy of a non empty ePtrList, with autoDelete enabled" + "We disable autoDelete in the new ePtrList !!"); + else + autoDelete=true; +} + +/////////////////// ePtrList Destructor ///////////////////////////// +template <class T> +inline ePtrList<T>::~ePtrList() +{ +// if autoDelete is enabled, delete is called for all elements in the list + if (autoDelete) + for (std_list_T_iterator it(std::list<T*>::begin()); it != std::list<T*>::end(); it++) + delete *it; +} + + +/////////////////// ePtrList sort() ///////////////////////// +template <class T> +inline void ePtrList<T>::sort() +{ +// Sorts all items in the list. +// The type T must have a operator <. + std::list<T*>::sort(ePtrList<T>::less()); +} + +/////////////////// ePtrList remove(T*) ///////////////////////// +template <class T> +inline void ePtrList<T>::remove(T* t) +{ +// Remove all items that, equals to t, if auto-deletion is enabled, than the list call delete for the removed items +// If current is equal to one of the removed items, current is set to the next valid item + T_iterator it(std::list<T*>::begin()); + + while (it != std::list<T*>::end()) + if (*it == t) + { + it=erase(it); + break; // one item is complete removed an deleted + } + else + it++; + + while (it != std::list<T*>::end()) + if (*it == t) + it = std::list<T*>::erase(it); // remove all other items that equals to t (no delete is called..) + else + it++; + +} + +/////////////////// ePtrList clear() ////////////////// +template <class T> +inline void ePtrList<T>::clear() +{ +// Remove all items from the list +// If auto-deletion is enabled, than the list call delete for all items in the list + erase(std::list<T*>::begin(), std::list<T*>::end()); +} + +/////////////////// ePtrList pop_back() //////////////////// +template <class T> +inline void ePtrList<T>::pop_back() +{ +// Removes the last item from the list. If the current item ist the last, than the current is set to the new +// last item in the list; +// The removed item is deleted if auto-deletion is enabled. + erase(--end()); +} + +/////////////////// ePtrList pop_front() //////////////////// +template <class T> +inline void ePtrList<T>::pop_front() +{ +// Removes the first item from the list. If the current item ist the first, than the current is set to the new +// first item in the list; +// The removed item is deleted if auto-deletion is enabled. + erase(begin()); +} + +/////////////////// ePtrList push_back(T*) //////////////////// +template <class T> +inline void ePtrList<T>::push_back(T* x) +{ +// Add a new item at the end of the list. +// The current item is set to the last item; + std::list<T*>::push_back(x); + last(); +} + +/////////////////// ePtrList push_front(T*) //////////////////// +template <class T> +inline void ePtrList<T>::push_front(T* x) +{ +// Add a new item at the begin of the list. +// The current item is set to the first item; + std::list<T*>::push_front(x); + first(); +} + +/////////////////// ePtrList take() //////////////////// +template <class T> +inline T* ePtrList<T>::take() +{ +// Takes the current item out of the list without deleting it (even if auto-deletion is enabled). +// Returns a pointer to the item taken out of the list, or null if the index is out of range. +// The item after the taken item becomes the new current list item if the taken item is not the last item in the list. If the last item is taken, the new last item becomes the current item. +// The current item is set to null if the list becomes empty. + T* tmp = *cur; + cur = std::list<T*>::erase(cur); + return tmp; +} + +/////////////////// ePtrList take(T*) //////////////////// +template <class T> +inline void ePtrList<T>::take(T* t) +{ +// Takes all item with T* out of the list without deleting it (even if auto-deletion is enabled). + std::list<T*>::remove(t); +} + +/////////////////// ePtrList setCurrent(T*) //////////////////// +template <class T> +inline T* ePtrList<T>::setCurrent(const T* t) +{ + // Sets the internal current iterator to the first element that equals to t, and returns t when a item is found, + // otherwise it returns 0 ! + for (T_iterator it(std::list<T*>::begin()); it != std::list<T*>::end(); ++it) + if (*it == t) + { + cur = it; + return *it; + } + + return 0; +} + +/////////////////// ePtrList current() //////////////////// +template <class T> +inline T* ePtrList<T>::current() +{ +// Returns a pointer to the current list item. The current item may be null (implies that the current index is -1). + return cur==end() ? 0 : *cur; +} + +/////////////////// ePtrList next() //////////////////// +template <class T> +inline T* ePtrList<T>::next() +{ +// Returns a pointer to the item succeeding the current item. Returns null if the current items is null or equal to the last item. +// Makes the succeeding item current. If the current item before this function call was the last item, the current item will be set to null. If the current item was null, this function does nothing. + if (cur == end()) + return 0; + else + if (++cur == end()) + return 0; + else + return *cur; +} + +/////////////////// ePtrList prev() //////////////////// +template <class T> +inline T* ePtrList<T>::prev() +{ +// Returns a pointer to the item preceding the current item. Returns null if the current items is null or equal to the first item. +// Makes the preceding item current. If the current item before this function call was the first item, the current item will be set to null. If the current item was null, this function does nothing. + if (cur == begin()) + return 0; + else + return *--cur; +} + +/////////////////// ePtrList first() //////////////////// +template <class T> +inline T* ePtrList<T>::first() +{ +// Returns a pointer to the first item in the list and makes this the current list item, or null if the list is empty. + return *(cur = begin()); +} + +/////////////////// ePtrList last() //////////////////// +template <class T> +inline T* ePtrList<T>::last() +{ +// Returns a pointer to the last item in the list and makes this the current list item, or null if the list is empty. + return *(cur = --end()); +} + +/////////////////// const ePtrList current() //////////////////// +template <class T> +inline const T* ePtrList<T>::current() const +{ +// Returns a pointer to the current list item. The current item may be null (implies that the current index is not valid) + return cur==end() ? 0 : *cur; +} + +/////////////////// const ePtrList next() //////////////////// +template <class T> +inline const T* ePtrList<T>::next() const +{ +// Returns a pointer to the item succeeding the current item. Returns null if the current items is null or equal to the last item. +// Makes the succeeding item current. If the current item before this function call was the last item, the current item will be set to null. If the current item was null, this function does nothing. + if (cur == end()) + return 0; + else + if (++cur == end()) + return 0; + else + return *cur; +} + +/////////////////// const ePtrList prev() //////////////////// +template <class T> +inline const T* ePtrList<T>::prev() const +{ +// Returns a pointer to the item preceding the current item. Returns null if the current items is null or equal to the first item. +// Makes the preceding item current. If the current item before this function call was the first item, the current item will be set to null. If the current item was null, this function does nothing. + if (cur == begin()) + return 0; + else + return *--cur; +} + +/////////////////// const ePtrList first() //////////////////// +template <class T> +inline const T* ePtrList<T>::first() const +{ +// Returns a pointer to the first item in the list and makes this the current list item, or null if the list is empty. + return *(cur = begin()); +} + +/////////////////// const ePtrList last() //////////////////// +template <class T> +inline const T* ePtrList<T>::last() const +{ +// Returns a pointer to the last item in the list and makes this the current list item, or null if the list is empty. + return *(cur = --end()); +} + +////////////////// struct less ////////////////////////////// +template <class T> +struct ePtrList<T>::less +{ +// operator() is used internal from the list to sort them + bool operator() (const T* t1, const T* t2) + { + return (*t1 < *t2); + } +}; + +/////////////////// ePtrList operator bool //////////////////// +template <class T> +ePtrList<T>::operator bool() +{ +// Returns a bool that contains true, when the list is NOT empty otherwise false + return !empty(); +} + +template <class T> +bool ePtrList<T>::operator!() +{ +// Returns a bool that contains true, when the list is empty otherwise false + return empty(); +} + +template <class T> +void ePtrList<T>::setAutoDelete(bool b) +{ +// switched autoDelete on or off +// if autoDelete is true, than the pointer list controls the heap memory behind the pointer itself +// the list calls delete for the item before it removed from the list + autoDelete=b; +} + +template <class T> +bool ePtrList<T>::isAutoDelete() +{ +// returns a bool that contains the state of autoDelete + return autoDelete; +} + +template <class T> +class eSmartPtrList : public std::list<ePtr<T> > +{ +public: + typedef typename std::list<ePtr<T>, std::allocator<ePtr<T> > >::iterator std_list_T_iterator; // to remove compiler warnings + typedef typename std::list<ePtr<T>, std::allocator<ePtr<T> > >::const_iterator std_list_T_const_iterator; + typedef typename std::list<ePtr<T>, std::allocator<ePtr<T> > >::reverse_iterator std_list_T_reverse_iterator; + typedef typename std::list<ePtr<T>, std::allocator<ePtr<T> > >::const_reverse_iterator std_list_T_const_reverse_iterator; + typedef typename eSmartPtrList<T>::iterator T_iterator; + typedef typename eSmartPtrList<T>::const_iterator T_const_iterator; + typedef typename eSmartPtrList<T>::reverse_iterator T_reverse_iterator; + typedef typename eSmartPtrList<T>::const_reverse_iterator T_const_reverse_iterator; + +// Iterator classes + class iterator; + class const_iterator; + class reverse_iterator; + class const_reverse_iterator; + +// Constructors + inline eSmartPtrList(); + inline eSmartPtrList(const eSmartPtrList&); + inline ~eSmartPtrList(); + +// overwritted sort method + inline void sort(); + +// changed methods for autodelete and current implementation + inline void remove(T* t); + inline void clear(); + inline void pop_back(); + inline void pop_front(); + inline void push_back(T*); + inline void push_front(T*); + +// added methods for current implementation +// inline T* take(); +// inline void take(T* t); + inline T* current(); + inline T* next(); + inline T* prev(); + inline T* first(); + inline T* last(); + inline T* setCurrent(const T*); + inline const T* current() const; + inline const T* next() const; + inline const T* prev() const; + inline const T* first() const; + inline const T* last() const; + +// added operator methods + inline operator bool(); + inline bool operator!(); + +// added methods for autodelete implementation + inline void setAutoDelete(bool b); + inline bool isAutoDelete(); + +// added compare struct ... to sort + struct less; +private: + iterator cur; + bool autoDelete; + +public: + iterator eSmartPtrList<T>::begin() + { + // makes implicit type conversion form std::list::iterator to eSmartPtrList::iterator + return std::list<ePtr<T> >::begin(); + } + + iterator eSmartPtrList<T>::end() + { + // makes implicit type conversion form std::list::iterator to eSmartPtrList::iterator + return std::list<ePtr<T> >::end(); + } + + const_iterator eSmartPtrList<T>::begin() const + { + // makes implicit type conversion form std::list::const_iterator to eSmartPtrList::const_iterator + return std::list<ePtr<T> >::begin(); + } + + const_iterator eSmartPtrList<T>::end() const + { + // makes implicit type conversion form std::list::const_iterator to eSmartPtrList::const_iterator + return std::list<ePtr<T> >::end(); + } + + reverse_iterator eSmartPtrList<T>::rbegin() + { + // makes implicit type conversion form std::list::reverse:_iterator to eSmartPtrList::reverse_iterator + return std::list<ePtr<T> >::rbegin(); + } + + reverse_iterator eSmartPtrList<T>::rend() + { + // makes implicit type conversion form std::list::reverse_iterator to eSmartPtrList::reverse_iterator + return std::list<ePtr<T> >::rend(); + } + + const_reverse_iterator eSmartPtrList<T>::rbegin() const + { + // makes implicit type conversion form std::list::const_reverse_iterator to eSmartPtrList::const_reverse_iterator + return std::list<ePtr<T> >::rbegin(); + } + + const_reverse_iterator eSmartPtrList<T>::rend() const + { + // makes implicit type conversion form std::list::const_reverse_iterator to eSmartPtrList::const_reverse_iterator + return std::list<ePtr<T> >::rend(); + } + + iterator eSmartPtrList<T>::erase(iterator it) + { + // Remove the item it, if auto-deletion is enabled, than the list call delete for this item + // If current is equal to the item that was removed, current is set to the next item in the list + if (autoDelete && *it) + delete *it; + + if (cur == it) + return cur = std::list<ePtr<T> >::erase(it); + else + return std::list<ePtr<T> >::erase(it); + } + + iterator eSmartPtrList<T>::erase(iterator from, iterator to) + { + // Remove all items between the to iterators from and to + // If auto-deletion is enabled, than the list call delete for all removed items + while (from != to) + from = erase(from); + + return from; + } + + operator iterator() + { + // Returns a iterator that equal to begin() of the list + return begin(); + } + + operator const_iterator() const + { + // Returns a const_iterator that equal to begin() of the list + return begin(); + } + + operator reverse_iterator() + { + // Returns a reverse_iterator that equal to rbegin() of the list + return rbegin(); + } + + operator const_reverse_iterator() const + { + // Returns a const_reverse_iterator that equal to rbegin() of the list + return rbegin(); + } + + std::vector<T>* getVector() + { + // Creates an vector and copys all elements to this vector + // returns a pointer to this new vector ( the reserved memory must deletet from the receiver !! ) + std::vector<T>* v=new std::vector<T>(); + v->reserve( size() ); + for ( std_list_T_iterator it( std::list<ePtr<T> >::begin() ); it != std::list<ePtr<T> >::end(); it++) + v->push_back( **it ); + + return v; + } + + inline iterator insert_in_order( T* e ) + { + // added a new item to the list... in order + // returns a iterator to the new item + return insert( std::lower_bound( std::list<ePtr<T> >::begin(), std::list<ePtr<T> >::end(), e ), e ); + } + +}; + +/////////////////// iterator class ///////////////////////////// +template <class T> +class eSmartPtrList<T>::iterator : public std::list<ePtr<T> >::iterator +{ +public: + // Constructors + iterator(const std_list_T_iterator& Q) : std_list_T_iterator(Q) { } + + // changed operator for pointer + T* operator->() const + { + return *std::list<ePtr<T> >::iterator::operator->(); + } + + operator T&() const + { + return *operator->(); + } + + operator T*() const + { + return operator->(); + } + + iterator& operator++() + { + std::list<ePtr<T> >::iterator::operator++(); + return *this; + } + + iterator operator++(int) + { + return std::list<ePtr<T> >::iterator::operator++(0); + } + + iterator& operator--() + { + std::list<ePtr<T> >::iterator::operator--(); + return *this; + } + + iterator operator--(int) + { + return std::list<ePtr<T> >::iterator::operator--(0); + } +}; + +/////////////////// const_iterator class ///////////////////////////// +template <class T> +class eSmartPtrList<T>::const_iterator : public std::list<ePtr<T> >::const_iterator +{ +public: + // Constructors + const_iterator(const std_list_T_const_iterator& Q) :std_list_T_const_iterator(Q) { } + + // changed operator for pointer + T* operator->() const + { + return *std::list<ePtr<T> >::const_iterator::operator->(); + } + + operator T&() const + { + return *operator->(); + } + + operator T*() const + { + return operator->(); + } + + const_iterator& operator++() + { + std::list<ePtr<T> >::const_iterator::operator++(); + return *this; + } + + const_iterator operator++(int) + { + return std::list<ePtr<T> >::const_iterator::operator++(0); + } + + const_iterator& operator--() + { + std::list<ePtr<T> >::const_iterator::operator--(); + return *this; + } + + const_iterator operator--(int) + { + return std::list<ePtr<T> >::const_iterator::operator--(0); + } +}; + +/////////////////// reverse_iterator class ///////////////////////////// +template <class T> +class eSmartPtrList<T>::reverse_iterator : public std::list<ePtr<T> >::reverse_iterator +{ +public: + // Constructors + reverse_iterator(const std_list_T_reverse_iterator& Q) :std_list_T_reverse_iterator(Q) { } + + // changed operators for pointer + T* operator->() const + { + return *std::list<ePtr<T> >::reverse_iterator::operator->(); + } + + operator T&() const + { + return *operator->(); + } + + operator T*() const + { + return operator->(); + } + + reverse_iterator& operator++() + { + std::list<ePtr<T> >::reverse_iterator::operator++(); + return *this; + } + + reverse_iterator operator++(int) + { + return std::list<ePtr<T> >::reverse_iterator::operator++(0); + } + + reverse_iterator& operator--() + { + std::list<ePtr<T> >::reverse_iterator::operator--(); + return *this; + } + + reverse_iterator operator--(int) + { + return std::list<ePtr<T> >::reverse_iterator::operator--(0); + } +}; + +/////////////////// const_reverse_iterator class ///////////////////////////// +template <class T> +class eSmartPtrList<T>::const_reverse_iterator : public std::list<ePtr<T> >::const_reverse_iterator +{ +public: + // Constructors + const_reverse_iterator(const std_list_T_const_reverse_iterator& Q) :std_list_T_const_reverse_iterator(Q) { } + + // changed operators for pointer + T* operator->() const + { + return *std::list<ePtr<T> >::const_reverse_iterator::operator->(); + } + + operator T&() const + { + return *operator->(); + } + + operator T*() const + { + return operator->(); + } + + const_reverse_iterator& operator++() + { + std::list<ePtr<T> >::const_reverse_iterator::operator++(); + return *this; + } + + const_reverse_iterator operator++(int) + { + return std::list<ePtr<T> >::const_reverse_iterator::operator++(0); + } + + const_reverse_iterator& operator--() + { + std::list<ePtr<T> >::const_reverse_iterator::operator--(); + return *this; + } + + const_reverse_iterator operator--(int) + { + return std::list<ePtr<T> >::const_reverse_iterator::operator--(0); + } +}; + +/////////////////// Default Constructor ///////////////////////////// +template <class T> +eSmartPtrList<T>::eSmartPtrList() + :cur(std::list<ePtr<T> >::begin()), autoDelete(false) +{ + +} + +/////////////////// Copy Constructor ///////////////////////////// +template <class T> +eSmartPtrList<T>::eSmartPtrList(const eSmartPtrList& e) + :std::list<ePtr<T> >(e), cur(e.cur), autoDelete( false ) +{ + if ( e.autoDelete ) + if ( e.size() ) + eDebug("Warning !! We make a Copy of a non empty eSmartPtrList, with autoDelete enabled" + "We disable autoDelete in the new eSmartPtrList !!"); + else + autoDelete=true; +} + +/////////////////// eSmartPtrList Destructor ///////////////////////////// +template <class T> +inline eSmartPtrList<T>::~eSmartPtrList() +{ +// if autoDelete is enabled, delete is called for all elements in the list + if (autoDelete) + for (std_list_T_iterator it(std::list<ePtr<T> >::begin()); it != std::list<ePtr<T> >::end(); it++) + delete *it; +} + + +/////////////////// eSmartPtrList sort() ///////////////////////// +template <class T> +inline void eSmartPtrList<T>::sort() +{ +// Sorts all items in the list. +// The type T must have a operator <. + std::list<ePtr<T> >::sort(eSmartPtrList<T>::less()); +} + +/////////////////// eSmartPtrList remove(T*) ///////////////////////// +template <class T> +inline void eSmartPtrList<T>::remove(T* t) +{ +// Remove all items that, equals to t, if auto-deletion is enabled, than the list call delete for the removed items +// If current is equal to one of the removed items, current is set to the next valid item + T_iterator it(std::list<ePtr<T> >::begin()); + + while (it != std::list<ePtr<T> >::end()) + if (*it == t) + { + it=erase(it); + break; // one item is complete removed an deleted + } + else + it++; + + while (it != std::list<ePtr<T> >::end()) + if (*it == t) + it = std::list<ePtr<T> >::erase(it); // remove all other items that equals to t (no delete is called..) + else + it++; + +} + +/////////////////// eSmartPtrList clear() ////////////////// +template <class T> +inline void eSmartPtrList<T>::clear() +{ +// Remove all items from the list +// If auto-deletion is enabled, than the list call delete for all items in the list + erase(std::list<ePtr<T> >::begin(), std::list<ePtr<T> >::end()); +} + +/////////////////// eSmartPtrList pop_back() //////////////////// +template <class T> +inline void eSmartPtrList<T>::pop_back() +{ +// Removes the last item from the list. If the current item ist the last, than the current is set to the new +// last item in the list; +// The removed item is deleted if auto-deletion is enabled. + erase(--end()); +} + +/////////////////// eSmartPtrList pop_front() //////////////////// +template <class T> +inline void eSmartPtrList<T>::pop_front() +{ +// Removes the first item from the list. If the current item ist the first, than the current is set to the new +// first item in the list; +// The removed item is deleted if auto-deletion is enabled. + erase(begin()); +} + +/////////////////// eSmartPtrList push_back(T*) //////////////////// +template <class T> +inline void eSmartPtrList<T>::push_back(T* x) +{ +// Add a new item at the end of the list. +// The current item is set to the last item; + std::list<ePtr<T> >::push_back(x); + last(); +} + +/////////////////// eSmartPtrList push_front(T*) //////////////////// +template <class T> +inline void eSmartPtrList<T>::push_front(T* x) +{ +// Add a new item at the begin of the list. +// The current item is set to the first item; + std::list<ePtr<T> >::push_front(x); + first(); +} + +/////////////////// eSmartPtrList take() //////////////////// +//template <class T> +//inline T* eSmartPtrList<T>::take() +//{ +//// Takes the current item out of the list without deleting it (even if auto-deletion is enabled). +//// Returns a pointer to the item taken out of the list, or null if the index is out of range. +//// The item after the taken item becomes the new current list item if the taken item is not the last item in the list. If the last item is taken, the new last item becomes the current item. +//// The current item is set to null if the list becomes empty. +// T* tmp = *cur; +// cur = std::list<T*>::erase(cur); +// return tmp; +//} + +/////////////////// eSmartPtrList take(T*) //////////////////// +//template <class T> +//inline void eSmartPtrList<T>::take(T* t) +//{ +//// Takes all item with T* out of the list without deleting it (even if auto-deletion is enabled). +// std::list<T*>::remove(t); +//} + +/////////////////// eSmartPtrList setCurrent(T*) //////////////////// +template <class T> +inline T* eSmartPtrList<T>::setCurrent(const T* t) +{ + // Sets the internal current iterator to the first element that equals to t, and returns t when a item is found, + // otherwise it returns 0 ! + for (T_iterator it(std::list<ePtr<T> >::begin()); it != std::list<ePtr<T> >::end(); ++it) + if (*it == t) + { + cur = it; + return *it; + } + + return 0; +} + +/////////////////// eSmartPtrList current() //////////////////// +template <class T> +inline T* eSmartPtrList<T>::current() +{ +// Returns a pointer to the current list item. The current item may be null (implies that the current index is -1). + return cur==end() ? 0 : *cur; +} + +/////////////////// eSmartPtrList next() //////////////////// +template <class T> +inline T* eSmartPtrList<T>::next() +{ +// Returns a pointer to the item succeeding the current item. Returns null if the current items is null or equal to the last item. +// Makes the succeeding item current. If the current item before this function call was the last item, the current item will be set to null. If the current item was null, this function does nothing. + if (cur == end()) + return 0; + else + if (++cur == end()) + return 0; + else + return *cur; +} + +/////////////////// eSmartPtrList prev() //////////////////// +template <class T> +inline T* eSmartPtrList<T>::prev() +{ +// Returns a pointer to the item preceding the current item. Returns null if the current items is null or equal to the first item. +// Makes the preceding item current. If the current item before this function call was the first item, the current item will be set to null. If the current item was null, this function does nothing. + if (cur == begin()) + return 0; + else + return *--cur; +} + +/////////////////// eSmartPtrList first() //////////////////// +template <class T> +inline T* eSmartPtrList<T>::first() +{ +// Returns a pointer to the first item in the list and makes this the current list item, or null if the list is empty. + return *(cur = begin()); +} + +/////////////////// eSmartPtrList last() //////////////////// +template <class T> +inline T* eSmartPtrList<T>::last() +{ +// Returns a pointer to the last item in the list and makes this the current list item, or null if the list is empty. + return *(cur = --end()); +} + +/////////////////// const eSmartPtrList current() //////////////////// +template <class T> +inline const T* eSmartPtrList<T>::current() const +{ +// Returns a pointer to the current list item. The current item may be null (implies that the current index is not valid) + return cur==end() ? 0 : *cur; +} + +/////////////////// const eSmartPtrList next() //////////////////// +template <class T> +inline const T* eSmartPtrList<T>::next() const +{ +// Returns a pointer to the item succeeding the current item. Returns null if the current items is null or equal to the last item. +// Makes the succeeding item current. If the current item before this function call was the last item, the current item will be set to null. If the current item was null, this function does nothing. + if (cur == end()) + return 0; + else + if (++cur == end()) + return 0; + else + return *cur; +} + +/////////////////// const eSmartPtrList prev() //////////////////// +template <class T> +inline const T* eSmartPtrList<T>::prev() const +{ +// Returns a pointer to the item preceding the current item. Returns null if the current items is null or equal to the first item. +// Makes the preceding item current. If the current item before this function call was the first item, the current item will be set to null. If the current item was null, this function does nothing. + if (cur == begin()) + return 0; + else + return *--cur; +} + +/////////////////// const eSmartPtrList first() //////////////////// +template <class T> +inline const T* eSmartPtrList<T>::first() const +{ +// Returns a pointer to the first item in the list and makes this the current list item, or null if the list is empty. + return *(cur = begin()); +} + +/////////////////// const eSmartPtrList last() //////////////////// +template <class T> +inline const T* eSmartPtrList<T>::last() const +{ +// Returns a pointer to the last item in the list and makes this the current list item, or null if the list is empty. + return *(cur = --end()); +} + +////////////////// struct less ////////////////////////////// +template <class T> +struct eSmartPtrList<T>::less +{ +// operator() is used internal from the list to sort them + bool operator() (const T* t1, const T* t2) + { + return (*t1 < *t2); + } +}; + +/////////////////// eSmartPtrList operator bool //////////////////// +template <class T> +eSmartPtrList<T>::operator bool() +{ +// Returns a bool that contains true, when the list is NOT empty otherwise false + return !empty(); +} + +template <class T> +bool eSmartPtrList<T>::operator!() +{ +// Returns a bool that contains true, when the list is empty otherwise false + return empty(); +} + +template <class T> +void eSmartPtrList<T>::setAutoDelete(bool b) +{ +// switched autoDelete on or off +// if autoDelete is true, than the pointer list controls the heap memory behind the pointer itself +// the list calls delete for the item before it removed from the list + autoDelete=b; +} + +template <class T> +bool eSmartPtrList<T>::isAutoDelete() +{ +// returns a bool that contains the state of autoDelete + return autoDelete; +} + +#endif // _E_PTRLIST diff --git a/lib/base/estring.cpp b/lib/base/estring.cpp new file mode 100644 index 00000000..bf30d5f9 --- /dev/null +++ b/lib/base/estring.cpp @@ -0,0 +1,468 @@ +#include <lib/base/estring.h> +#include <ctype.h> +#include <limits.h> +#include <lib/base/elock.h> + +static pthread_mutex_t lock=PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP; + +///////////////////////////////////////// eString sprintf ///////////////////////////////////////////////// +eString& eString::sprintf(char *fmt, ...) +{ + singleLock s(lock); +// Implements the normal sprintf method, to use format strings with eString +// The max length of the result string is 1024 char. + static char buf[1024]; + va_list ap; + va_start(ap, fmt); + std::vsnprintf(buf, 1024, fmt, ap); + va_end(ap); + assign(buf); + return *this; +} + +///////////////////////////////////////// eString setNum(uint, uint) /////////////////////////////////////// +eString& eString::setNum(int val, int sys) +{ +// Returns a string that contain the value val as string +// if sys == 16 than hexadezimal if sys == 10 than decimal + char buf[12]; + + if (sys == 10) + std::snprintf(buf, 12, "%i", val); + else if (sys == 16) + std::snprintf(buf, 12, "%X", val); + + assign(buf); + return *this; +} + +///////////////////////////////////////// eString replaceChars(char, char) ///////////////////////////// +eString& eString::removeChars(char fchar) +{ +// Remove all chars that equal to fchar, and returns a reference to itself + unsigned int index=0; + + while ( ( index = find(fchar, index) ) != npos ) + erase(index, 1); + + return *this; +} + +/////////////////////////////////////// eString upper() //////////////////////////////////////////////// +eString& eString::upper() +{ +// convert all lowercase characters to uppercase, and returns a reference to itself + for (iterator it = begin(); it != end(); it++) + switch(*it) + { + case 'a' ... 'z' : + *it -= 32; + break; + + case 'ä' : + *it = 'Ä'; + break; + + case 'ü' : + *it = 'Ü'; + break; + + case 'ö' : + *it = 'Ö'; + break; + } + + return *this; +} + +eString& eString::strReplace(const char* fstr, const eString& rstr) +{ +// replace all occurrence of fstr with rstr and, and returns a reference to itself + unsigned int index=0; + unsigned int fstrlen = strlen(fstr); + int rstrlen=rstr.size(); + + while ( ( index = find(fstr, index) ) != npos ) + { + replace(index, fstrlen, rstr); + index+=rstrlen; + } + + return *this; +} + +int strnicmp(const char *s1, const char *s2, int len) +{ +// makes a case insensitive string compare with len Chars + while ( *s1 && *s2 && len-- ) + if ( tolower(*s1) != tolower(*s2) ) + return tolower(*s1) < tolower(*s2) ? -1 : 1; + else + s1++, s2++; + + return 0; +} + +/////////////////////////////////////// eString icompare(const eString&) //////////////////////////////////////////////// +int eString::icompare(const eString& s) +{ +// makes a case insensitive string compare + std::string::const_iterator p = begin(), + p2 = s.begin(); + + while ( p != end() && p2 != s.end() ) + if ( tolower(*p) != tolower(*p2) ) + return tolower(*p) < tolower(*p2) ? -1 : 1; + else + p++, p2++; + + return length() == s.length() ? 0 : length() < s.length() ? -1 : 1; +} + + // 8859-x to dvb coding tables. taken from www.unicode.org/Public/MAPPINGS/ISO8859/ +static unsigned long c88595[128]={ +0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, +0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, +0x00a0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x00ad, 0x040e, 0x040f, +0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, +0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, +0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, +0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, +0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x00a7, 0x045e, 0x045f}; + +static unsigned long c88596[128]={ +0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, +0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, +0x00a0, 0x0000, 0x0000, 0x0000, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x060c, 0x00ad, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f, +0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, +0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, +0x0650, 0x0651, 0x0652, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; + +static unsigned long c88597[128]={ +0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, +0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, +0x00a0, 0x2018, 0x2019, 0x00a3, 0x0000, 0x0000, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x0000, 0x00ab, 0x00ac, 0x00ad, 0x0000, 0x2015, +0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x0385, 0x0386, 0x00b7, 0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f, +0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, +0x03a0, 0x03a1, 0x0000, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af, +0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, +0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x0000}; + +static unsigned long c88598[128]={ +0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, +0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, +0x00a0, 0x0000, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, +0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2017, +0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, +0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x0000, 0x0000, 0x200e, 0x200f, 0x0000}; + +static unsigned long c88599[128]={ +0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, +0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, +0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, +0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, +0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, +0x011e, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0130, 0x015e, 0x00df, +0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, +0x011f, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0131, 0x015f, 0x00ff}; + + // UPC Direct / HBO strange two-character encoding. 0xC2 means acute, 0xC8 doule 'dot', 0xCA small 'circle', 0xCD double 'acute', 0xCF acute. + // many thanks to the czechs who helped me while solving this. +static inline unsigned int doCzech(int c1, int c2) +{ + switch (c1) + { + case 0xC2: // acute + switch (c2) + { + case 'A': return 0x00C1; + case 'a': return 0x00E1; + case 'E': return 0x00C9; + case 'e': return 0x00E9; + case 'I': return 0x00CD; + case 'i': return 0x00ED; + case 'O': return 0x00D3; + case 'o': return 0x00F3; // corrected, was 0x00E3 + case 'U': return 0x00DA; + case 'u': return 0x00FA; + case 'Y': return 0x00DD; + case 'y': return 0x00FD; + default: + return 0; + } + case 0xC8: // double 'dot' + switch (c2) + { + case 'A': return 0x00C4; + case 'a': return 0x00E4; + case 'E': return 0x00CB; + case 'e': return 0x00EB; + case 'O': return 0x00D6; + case 'o': return 0x00F6; + case 'U': return 0x00DC; + case 'u': return 0x00FC; + default: + return 0; + } + case 0xCA: // small 'circle' + switch (c2) + { + case 'U': return 0x016E; + case 'u': return 0x016F; + default: + return 0; + } + case 0xCD: // double 'acute' + switch (c2) + { + case 'O': return 0x0150; + case 'o': return 0x0151; + case 'U': return 0x0170; + case 'u': return 0x0171; + default: + return 0; + } + case 0xCF: // caron + switch (c2) + { + case 'C': return 0x010C; + case 'c': return 0x010D; + case 'D': return 0x010E; + case 'd': return 0x010F; + case 'E': return 0x011A; + case 'e': return 0x011B; + case 'L': return 0x013D; // not sure if they really exist. + case 'l': return 0x013E; + case 'N': return 0x0147; + case 'n': return 0x0148; + case 'R': return 0x0158; + case 'r': return 0x0159; + case 'S': return 0x0160; + case 's': return 0x0161; + case 'T': return 0x0164; + case 't': return 0x0165; + case 'Z': return 0x017D; + case 'z': return 0x017E; + default: + return 0; + } + default: + return 0; + } +} + +static inline unsigned int recode(unsigned char d, int cp) +{ + if (d < 0x80) + return d; + switch (cp) + { + case 0: // 8859-1 Latin1 <-> unicode mapping + return d; + case 1: // 8859-5 -> unicode mapping + return c88595[d-0x80]; + case 2: // 8859-6 -> unicode mapping + return c88596[d-0x80]; + case 3: // 8859-7 -> unicode mapping + return c88597[d-0x80]; + case 4: // 8859-8 -> unicode mapping + return c88598[d-0x80]; + case 5: // 8859-9 -> unicode mapping + return c88599[d-0x80]; + default: + return d; + } +} + +eString convertDVBUTF8(unsigned char *data, int len, int table) +{ + int i; + if (!len) + return ""; + + i=0; + if (data[0] <= 5) + table=data[i++]; + if ((data[0] >= 0x10) && (data[0] <= 0x12)) + return "<unsupported encoding>"; + + int bytesneeded=0, t=0, s=i; + + for (; i<len; ++i) + { + unsigned long code=0; + if ((table == 5) && ((data[i] == 0xC2) || (data[i] == 0xC8) || (data[i] == 0xCA) || (data[i] == 0xCD) || (data[i] == 0xCF)) && (i+1 < len)) + // braindead czech encoding... + if ((code=doCzech(data[i], data[i+1]))) + ++i; + if (!code) + code=recode(data[i], table); + if (!code) + continue; + if (code >= 0x10000) + bytesneeded++; + if (code >= 0x800) + bytesneeded++; + if (code >= 0x80) + bytesneeded++; + bytesneeded++; + } + + i=s; + + unsigned char res[bytesneeded]; + + while (i < len) + { + unsigned long code=0; + if ((table == 5) && ((data[i] == 0xC2) || (data[i] == 0xC8) || (data[i] == 0xCA) || (data[i] == 0xCD) || (data[i] == 0xCF)) && (i+1 < len)) + // braindead czech encoding... + if ((code=doCzech(data[i], data[i+1]))) + i+=2; + if (!code) + code=recode(data[i++], table); + if (!code) + continue; + // Unicode->UTF8 encoding + if (code < 0x80) // identity ascii <-> utf8 mapping + res[t++]=char(code); + else if (code < 0x800) // two byte mapping + { + res[t++]=(code>>6)|0xC0; + res[t++]=(code&0x3F)|0x80; + } else if (code < 0x10000) // three bytes mapping + { + res[t++]=(code>>12)|0xE0; + res[t++]=((code>>6)&0x3F)|0x80; + res[t++]=(code&0x3F)|0x80; + } else + { + res[t++]=(code>>18)|0xF0; + res[t++]=((code>>12)&0x3F)|0x80; + res[t++]=((code>>6)&0x3F)|0x80; + res[t++]=(code&0x3F)|0x80; + } + } + if ( t != bytesneeded) + eFatal("t: %d, bytesneeded: %d", t, bytesneeded); + return eString().assign((char*)res, t); +} + +eString convertUTF8DVB(const eString &string) +{ + eString ss=eString(); + + int len=string.length(); + for(int i=0;i<len;i++){ + unsigned char c1=string[i]; + unsigned int c; + if(c1<0x80) + c=c1; + else{ + i++; + unsigned char c2=string[i]; + c=((c1&0x3F)<<6) + (c2&0x3F); + } + // c = UNICODE + // now search it in table + if(c>=0x80){ + for(unsigned int j=0;j<128;j++){ + if(c88599[j]==c){ // now only 8859-9 .... + c=0x80+j; + break; + } + } + } + ss+=c; + } + + return ss; +} + +eString convertLatin1UTF8(const eString &string) +{ + unsigned int bytesneeded=0, t=0, i; + + unsigned int len=string.size(); + + for (i=0; i<len; ++i) + { + unsigned long code=string[i]; + if (!code) + continue; + if (code >= 0x10000) + bytesneeded++; + if (code >= 0x800) + bytesneeded++; + if (code >= 0x80) + bytesneeded++; + bytesneeded++; + } + + i=0; + + unsigned char res[bytesneeded]; + + while (i < len) + { + unsigned long code=string[i++]; + // Unicode->UTF8 encoding + if (code < 0x80) // identity latin <-> utf8 mapping + res[t++]=char(code); + else if (code < 0x800) // two byte mapping + { + res[t++]=(code>>6)|0xC0; + res[t++]=(code&0x3F)|0x80; + } else if (code < 0x10000) // three bytes mapping + { + res[t++]=(code>>12)|0xE0; + res[t++]=((code>>6)&0x3F)|0x80; + res[t++]=(code&0x3F)|0x80; + } else + { + res[t++]=(code>>18)|0xF0; + res[t++]=((code>>12)&0x3F)|0x80; + res[t++]=((code>>6)&0x3F)|0x80; + res[t++]=(code&0x3F)|0x80; + } + } + if ( t != bytesneeded) + eFatal("t: %d, bytesneeded: %d", t, bytesneeded); + return eString().assign((char*)res, t); +} + +int isUTF8(const eString &string) +{ + unsigned int len=string.size(); + + for (unsigned int i=0; i < len; ++i) + { + if (!(string[i]&0x80)) // normal ASCII + continue; + if ((string[i] & 0xE0) == 0xC0) // one char following. + { + // first, length check: + if (i+1 >= len) + return 0; // certainly NOT utf-8 + i++; + if ((string[i]&0xC0) != 0x80) + return 0; // no, not UTF-8. + } else if ((string[i] & 0xF0) == 0xE0) + { + if ((i+1) >= len) + return 0; + i++; + if ((string[i]&0xC0) != 0x80) + return 0; + i++; + if ((string[i]&0xC0) != 0x80) + return 0; + } + } + return 1; // can be UTF8 (or pure ASCII, at least no non-UTF-8 8bit characters) +} + diff --git a/lib/base/estring.h b/lib/base/estring.h new file mode 100644 index 00000000..36f6636a --- /dev/null +++ b/lib/base/estring.h @@ -0,0 +1,113 @@ +#ifndef __E_STRING__ +#define __E_STRING__ + +#include <string> +#include <stdarg.h> +#include <stdio.h> +#include "eerror.h" + +int strnicmp(const char*, const char*, int); + +class eString : public std::string +{ +public: +// constructors + inline eString() {} + inline eString(const char* p); + inline eString(const char* p, int cnt); + inline eString(const std::string &s); +// methods + inline eString left(unsigned int len) const; + inline eString mid(unsigned int index, unsigned int len=(unsigned)-1) const; + inline eString right(unsigned int len) const; + bool isNull() const; +// operators + inline operator bool() const; + inline bool operator!() const; +// methods with implementation in estring.cpp + eString& sprintf(char *fmt, ...); + eString& setNum(int val, int sys=10); + eString& removeChars(const char fchar); + eString& strReplace(const char* fstr, const eString& rstr); + eString& upper(); + int icompare(const eString& s); +}; + +eString convertDVBUTF8(unsigned char *data, int len, int table=5); +eString convertUTF8DVB(const eString &string); // with default ISO8859-5 +eString convertLatin1UTF8(const eString &string); +int isUTF8(const eString &string); + +/////////////////////////////////////////////// Copy Constructors //////////////////////////////////////////////// +inline eString::eString(const std::string &s) + :std::string(s) +{ +} + +inline eString::eString(const char* p) + :std::string(p?p:"") // when the char* p is null, than use ""... otherwise crash... +{ +} + +inline eString::eString(const char* p, int cnt) + :std::string(p, cnt) +{ +} + +///////////////////////////////////////// eString operator bool ///////////////////////////////////////////////// +inline eString::operator bool() const +{ +// Returns a bool that contains true if the string longer than 0 Character otherwise false; + return !empty(); +} + +///////////////////////////////////////// eString operator! //////////////////////////////////////////////////// +inline bool eString::operator!() const +{ +// Returns a bool that contains true if the string ist empty otherwise false; + return empty(); +} + +///////////////////////////////////////// eString left ////////////////////////////////////////////////////////// +inline eString eString::left(unsigned int len) const +{ +// Returns a substring that contains the len leftmost characters of the string. +// The whole string is returned if len exceeds the length of the string. + return len >= length() ? *this : substr(0, len); +} + +//////////////////////////////////////// eString mid //////////////////////////////////////////////////////////// +inline eString eString::mid(unsigned int index, unsigned int len) const +{ +// Returns a substring that contains the len characters of this string, starting at position index. +// Returns a null string if the string is empty or index is out of range. Returns the whole string from index if index+len exceeds the length of the string. + register unsigned int strlen = length(); + + if (index >= strlen) + return eString(); + + if (len == (unsigned)-1) + return substr(index); + + if (strlen < index + len) + len = strlen-index; + + return substr(index, len); +} + +//////////////////////////////////////// eString right //////////////////////////////////////////////////////////// +inline eString eString::right(unsigned int len) const +{ +// Returns a substring that contains the len rightmost characters of the string. +// The whole string is returned if len exceeds the length of the string. + register unsigned int strlen = length(); + return len >= strlen ? *this : substr(strlen-len, len); +} + +inline bool eString::isNull() const +{ +// Returns a bool, that contains true, when the internal char* is null (only when a string ist empty constructed) + return !c_str(); +} + +#endif // __E_STRING__ diff --git a/lib/base/i18n.h b/lib/base/i18n.h new file mode 100644 index 00000000..96d5402b --- /dev/null +++ b/lib/base/i18n.h @@ -0,0 +1,29 @@ +/* + * i18n.h: gettext defines and includes + * + * Copyright (C) 2002 Bastian Blank <waldi@tuxbox.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: i18n.h,v 1.1 2003-10-17 15:35:47 tmbinc Exp $ + */ + +#ifndef __CORE__BASE__I18N_H +#define __CORE__BASE__I18N_H + +#include <libintl.h> +#define _(string) gettext (string) + +#endif diff --git a/lib/base/init.cpp b/lib/base/init.cpp new file mode 100644 index 00000000..b9cf1dec --- /dev/null +++ b/lib/base/init.cpp @@ -0,0 +1,68 @@ +#include <stdio.h> +#include <lib/base/init.h> +#include <lib/base/eerror.h> + +int eInit::rl=-1; +std::list<std::pair<int,eAutoInit*> > *eInit::cl; + +void eInit::add(int trl, eAutoInit *c) +{ + if (!cl) + cl=new std::list<std::pair<int,eAutoInit*> >; + cl->push_back(std::pair<int,eAutoInit*>(trl, c)); + if (rl>=trl) + c->initNow(); +} + +void eInit::remove(int trl, eAutoInit *c) +{ + if (!cl) + return; + cl->remove(std::pair<int,eAutoInit*>(trl, c)); + if (rl>=trl) + c->closeNow(); +} + +eInit::eInit() +{ +} + +eInit::~eInit() +{ + setRunlevel(-1); + delete cl; + cl=0; +} + +void eInit::setRunlevel(int nrl) +{ + while (nrl>rl) + { + rl++; + + for (std::list<std::pair<int,eAutoInit*> >::iterator i(cl->begin()); i!=cl->end(); ++i) + { + if ((*i).first == rl) + { + eDebug("+ (%d) %s", rl, (*i).second->getDescription()); + (*i).second->initNow(); + } + } + } + + while (nrl<rl) + { + for (std::list<std::pair<int,eAutoInit*> >::iterator i(cl->begin()); i!=cl->end(); ++i) + if ((*i).first == rl) + { + eDebug("- (%d) %s", rl, (*i).second->getDescription()); + (*i).second->closeNow(); + } + rl--; + } + eDebug("reached rl %d", rl); +} + +eAutoInit::~eAutoInit() +{ +} diff --git a/lib/base/init.h b/lib/base/init.h new file mode 100644 index 00000000..465bac40 --- /dev/null +++ b/lib/base/init.h @@ -0,0 +1,97 @@ +#ifndef __init_h +#define __init_h + +#include <list> +#include <utility> + +class eAutoInit; + +class eInit +{ + static std::list<std::pair<int,eAutoInit*> > *cl; + friend class eAutoInit; + static int rl; +public: + eInit(); + ~eInit(); + static void setRunlevel(int rlev); + static void add(int trl, eAutoInit *c); + static void remove(int trl, eAutoInit *c); +}; + +class eAutoInit +{ + friend class eInit; + virtual void initNow()=0; + virtual void closeNow()=0; +protected: + int rl; + char *description; +public: + eAutoInit(int rl, char *description): rl(rl), description(description) + { + } + virtual ~eAutoInit(); + const char *getDescription() const { return description; }; +}; + +template<class T1, class T2> class +eAutoInitP1: protected eAutoInit +{ + T1 *t; + const T2 &arg; + void initNow() + { + t=new T1(arg); + } + void closeNow() + { + delete t; + } +public: + operator T1*() + { + return t; + } + eAutoInitP1(const T2 &arg, int runl, char *description): eAutoInit(runl, description), arg(arg) + { + eInit::add(rl, this); + } + ~eAutoInitP1() + { + eInit::remove(rl, this); + } +}; + +template<class T1> class +eAutoInitP0: protected eAutoInit +{ + T1 *t; + void initNow() + { + t=new T1(); + } + void closeNow() + { + delete t; + } +public: + operator T1*() + { + return t; + } + T1 *operator->() + { + return t; + } + eAutoInitP0(int runl, char *description): eAutoInit(runl, description) + { + eInit::add(rl, this); + } + ~eAutoInitP0() + { + eInit::remove(rl, this); + } +}; + +#endif diff --git a/lib/base/init_num.h b/lib/base/init_num.h new file mode 100644 index 00000000..a9da0624 --- /dev/null +++ b/lib/base/init_num.h @@ -0,0 +1,24 @@ +#ifndef __lib_system_init_num_ +#define __lib_system_init_num_ + +namespace eAutoInitNumbers +{ + enum { increment=5 }; + enum + { + configuration=0, + lowlevel=configuration+increment, + graphic=lowlevel+increment, + skin=graphic+increment, + rc=skin+increment, + guiobject=rc+increment, + actions=guiobject+increment, + dvb=actions+increment, + service=dvb+increment, + osd=service+increment, + wizard=osd+increment, + main=osd+increment*5, + }; +}; + +#endif diff --git a/lib/base/message.cpp b/lib/base/message.cpp new file mode 100644 index 00000000..dafbf3f8 --- /dev/null +++ b/lib/base/message.cpp @@ -0,0 +1,49 @@ +#include <lib/base/message.h> +#include <unistd.h> +#include <lib/base/eerror.h> + +eMessagePump::eMessagePump(int mt): content(1024*1024), ismt(mt) +{ + pipe(fd); +} + +eMessagePump::~eMessagePump() +{ + if (ismt) + content.lock(); // blocks until all messages are processed. + close(fd[0]); + close(fd[1]); +} + +int eMessagePump::send(const void *data, int len) +{ + if (ismt) + content.lock(len); + return ::write(fd[1], data, len)<0; +} + +int eMessagePump::recv(void *data, int len) +{ + unsigned char*dst=(unsigned char*)data; + while (len) + { + if (ismt) + content.unlock(len); + int r=::read(fd[0], dst, len); + if (r<0) + return r; + dst+=r; + len-=r; + } + return 0; +} + +int eMessagePump::getInputFD() const +{ + return fd[1]; +} + +int eMessagePump::getOutputFD() const +{ + return fd[0]; +} diff --git a/lib/base/message.h b/lib/base/message.h new file mode 100644 index 00000000..6a9ff43e --- /dev/null +++ b/lib/base/message.h @@ -0,0 +1,64 @@ +#ifndef __lib_base_message_h +#define __lib_base_message_h + +#include <lib/base/ebase.h> +#include <unistd.h> +#include <lib/base/elock.h> + +/** + * \brief A generic messagepump. + * + * You can send and receive messages with this class. Internally a fifo is used, + * so you can use them together with a \c eMainloop. + */ +class eMessagePump +{ + int fd[2]; + eLock content; + int ismt; +public: + eMessagePump(int mt=0); + ~eMessagePump(); + int send(const void *data, int len); + int recv(void *data, int len); // blockierend + int getInputFD() const; + int getOutputFD() const; +}; + +/** + * \brief A messagepump with fixed-length packets. + * + * Based on \ref eMessagePump, with this class you can send and receive fixed size messages. + * Automatically creates a eSocketNotifier and gives you a callback. + */ +template<class T> +class eFixedMessagePump: private eMessagePump, public Object +{ + eSocketNotifier *sn; + void do_recv(int) + { + T msg; + recv(&msg, sizeof(msg)); + /*emit*/ recv_msg(msg); + } +public: + Signal1<void,const T&> recv_msg; + void send(const T &msg) + { + eMessagePump::send(&msg, sizeof(msg)); + } + eFixedMessagePump(eMainloop *context, int mt): eMessagePump(mt) + { + sn=new eSocketNotifier(context, getOutputFD(), eSocketNotifier::Read); + CONNECT(sn->activated, eFixedMessagePump<T>::do_recv); + sn->start(); + } + ~eFixedMessagePump() + { + delete sn; + } + void start() { sn->start(); } + void stop() { sn->stop(); } +}; + +#endif diff --git a/lib/base/nconfig.cpp b/lib/base/nconfig.cpp new file mode 100644 index 00000000..a0e4a313 --- /dev/null +++ b/lib/base/nconfig.cpp @@ -0,0 +1,1027 @@ +// this is nconfig 0.92, a bit modified +#define NO_MAP_SHARED +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> +#include <lib/base/nconfig.h> + +#include <fcntl.h> +#include <string.h> +#include <memory.h> +#include <sys/types.h> +#include <unistd.h> +#include <sched.h> + +#include <sys/mman.h> + +#include <limits.h> + +#ifndef PAGESIZE +#ifdef PAGE_SIZE +#define PAGESIZE PAGE_SIZE +#else +#define PAGESIZE 4096 +#endif +#endif + +#define SB ((struct nc_sb_s *) data) +#define CM(x) ((struct nc_chunk_s *) (data+(x))) +#define DE(x) ((struct nc_de_s *) (data+(x))) +#define IDE(x, y) (DE(((unsigned *) (data+(x)->offset))[(y)])) +#define CS(x) (((unsigned *) (data+(x)))[-1]) + +inline unsigned NConfig::crc(const char *d, unsigned len) +{ + unsigned ret = 0; + unsigned l = len / sizeof(unsigned); + + while (l) { + ret += *(const unsigned *)d; + ret = (ret << 3) & (ret >> 29); + l--; + d += sizeof(unsigned); + } + return ret; +} + +NConfig::NConfig(int protect) +{ + fd = -1; + cname = fname = data = NULL; + sb = NULL; + cdir = NULL; + chunks = NULL; + revision = update = lsize = omode = 0; + olck = 0; + lock = NC_L_NONE; + careful = protect; +} + +NConfig::~NConfig() +{ + close(); + free(fname); +} + +void NConfig::close() +{ + free(cname); + cname = NULL; + if (fd > -1) { +#ifdef NO_MAP_SHARED + if (data) { + int size=sb->size; + char *buffer=new char[size]; + memcpy(buffer, data, size); + munmap(data, size); + data = NULL; + ::lseek(fd, 0, SEEK_SET); + ::write(fd, buffer, size); + delete[] buffer; + } +#endif + ::close(fd); + fd = -1; + } + if (data) { + munmap(data, sb->size); + data = NULL; + } +} + +void NConfig::flush() +{ + close(); + open(omode); +} + +int NConfig::setName(const char *name) +{ + if (!name) + return NC_ERR_NVAL; + if (fd > -1) + return NC_ERR_PERM; + free(fname); + fname = strdup(name); + return NC_ERR_OK; +} + +int NConfig::createNew(unsigned resize, unsigned dirent, unsigned mchunks) +{ + if (fd > -1) + return NC_ERR_NVAL; + if (!access(fname, F_OK)) + return NC_ERR_PERM; + + int ff; + if ((ff = ::open(fname, O_WRONLY | O_CREAT, 0600)) == -1) + return NC_ERR_NFILE; + struct nc_sb_s bsb = {NC_SB_MAGIC, resize*PAGESIZE, + dirent, mchunks, resize, mchunks, + sizeof(struct nc_sb_s)+sizeof(struct nc_de_s)+2*sizeof(unsigned), + sizeof(struct nc_sb_s), 0}; + struct nc_de_s bde = {sizeof(struct nc_sb_s)+sizeof(struct nc_de_s), + NC_DIR, sizeof(struct nc_sb_s), 0, 0, 0}; + struct nc_chunk_s bcm; + + write(ff, &bsb, sizeof(bsb)); + write(ff, &bde, sizeof(bde)); + write(ff, "/", 2); + + lseek(ff, sizeof(unsigned)-2, SEEK_CUR); + unsigned cl = sizeof(nc_chunk_s)*mchunks+sizeof(unsigned); + write(ff, &cl, sizeof(unsigned)); + + bcm.offset = bsb.chunk + sizeof(struct nc_chunk_s)*mchunks; + bcm.size = bsb.size - bcm.offset; + + write(ff, &bcm, sizeof(bcm)); + + lseek(ff, bsb.size-1, SEEK_SET); + write(ff, "", 1); + ::close(ff); + return NC_ERR_OK; +} + + +int NConfig::open(int how) +{ + if (!fname) + return NC_ERR_NFILE; + if (how != NC_O_RO && how != NC_O_RW) + return NC_ERR_TYPE; + if (fd > -1) + close(); + + int ff; + if ((ff = ::open(fname, how)) == -1) + return NC_ERR_PERM; + + struct stat sbuf; + fstat(ff, &sbuf); + + if (!sbuf.st_size) + return NC_ERR_CORRUPT; + +#ifdef NO_MAP_SHARED + if ((data = (char *) mmap(NULL, sbuf.st_size, how == NC_O_RO ? PROT_READ : (PROT_READ|PROT_WRITE), MAP_PRIVATE, ff, 0)) == MAP_FAILED) { +#else + if ((data = (char *) mmap(NULL, sbuf.st_size, how == NC_O_RO ? PROT_READ : (PROT_READ|PROT_WRITE), MAP_SHARED, ff, 0)) == MAP_FAILED) { +#endif + ::close(ff); + return NC_ERR_NMEM; + } + if (memcmp(((struct nc_sb_s *) data)->magic, NC_SB_MAGIC, 4)) { + munmap(data, sbuf.st_size); + ::close(ff); + return NC_ERR_CORRUPT; + } + fd = ff; + omode = how; + sb = SB; + lsize = 0; + cname = strdup("/"); + + lockFile(NC_L_RO, TRUE); + rdir = DE(sb->root); + unLockFile(); + return NC_ERR_OK; +} + +void NConfig::expand(unsigned toadd) +{ + unsigned nsize = sb->size + toadd; + lseek(fd, nsize-1, SEEK_SET); + write(fd, "", 1); + _remap(sb->size, nsize); + sb->size = nsize; + cdir = getDirEnt(cname); + chunks = CM(sb->chunk); +#ifdef NC_DEBUG_ALLOC + fprintf(stderr, "Expanded from %u to %u\n", nsize-toadd, nsize); +#endif +} + +unsigned NConfig::getChunk(unsigned s) +{ + int lst = -1; + + // Make sure we get aligned data + s = alignSize(s) + sizeof(unsigned); + +#ifdef NC_DEBUG_ALLOC + fprintf(stderr, "Taking %u (total %u)\n", s, sb->chunk_ttl); +#endif + + do { + int left = 0, right = sb->chunk_ttl - 1, c; + while (left <= right) { + int diff = chunks[c = (left + right) / 2].size - s; + if (diff < 0 || diff == sizeof(unsigned)) { +#ifdef NC_DEBUG_ALLOC + if (diff > 0) + fprintf(stderr, "Rejected chunk %d (%u:%u)\n", c, chunks[c].offset, chunks[c].size); +#endif + right = c - 1; + continue; + } + lst = c; + if (!diff) + break; + left = c + 1; + } + if (lst < 0) { + unsigned ll = (s / (sb->size_inc*PAGESIZE) + 1) * PAGESIZE * sb->size_inc; + // we don't have a suitable chunk + expand(ll); + // insert new chunk into list (always succeeds) + *(unsigned *)(data+sb->size-ll) = ll; + fast_free(sb->size-ll+sizeof(unsigned)); + } + } while (lst < 0); + +#ifdef NC_DEBUG_ALLOC + fprintf(stderr, "haluz 7: off = %u size = %u\n", chunks[7].offset, chunks[7].size); + fprintf(stderr, "Got %u chunk (pos %d), taking %u\n", chunks[lst].size, lst, s); + fprintf(stderr, "chunk (%u:%u)\n", chunks[lst].offset, chunks[lst].size); +#endif + + unsigned best = chunks[lst].offset+sizeof(unsigned); + memset(data+best, 0, s-sizeof(unsigned)); + chunks[lst].size -= s; + chunks[lst].offset += s; + CS(best) = s; + + while (lst < ((signed)sb->chunk_ttl - 1) && chunks[lst].size < chunks[lst+1].size) { + unsigned b = chunks[lst].size; + unsigned i = lst + 1; + chunks[lst].size = chunks[i].size; + chunks[i].size = b; + b = chunks[lst].offset; + chunks[lst].offset = chunks[i].offset; + chunks[i].offset = b; + lst = i; + } + +#ifdef NC_DEBUG_ALLOC + fprintf(stderr, "Returned %u:%u\n", best, CS(best)); +#endif + return best; +} + +void NConfig::freeChunk(unsigned where) +{ +#ifdef NC_DEBUG_ALLOC + fprintf(stderr, "Free chunk: %u\n", CS(where)); +#endif + if (chunks[sb->chunk_ttl-2].size) { +#ifdef NC_DEBUG_ALLOC + fprintf(stderr, "Last slot available.\n"); +#endif + unsigned n = getChunk((sb->chunk_ttl+sb->chunk_inc)*sizeof(struct nc_chunk_s)); + unsigned f = sb->chunk; + memcpy(data+n, chunks, (sb->chunk_ttl-1)*sizeof(struct nc_chunk_s)); + chunks = CM(sb->chunk = n); + sb->chunk_ttl += sb->chunk_inc; + fast_free(f); + } + fast_free(where); +} + +inline unsigned NConfig::alignSize(unsigned s) +{ + unsigned of = s % sizeof(unsigned); + return of ? s + sizeof(unsigned) - of : s; +} + +void NConfig::delKey(const char *name) +{ + _delKey(name, NULL, TRUE); +} + +void NConfig::_delKey(const char *name, struct nc_de_s *p, int tosort) +{ + if (fd < 0) + return; + lockFile(NC_L_RW); + struct nc_de_s *nd = getDirEnt(name, p); + if (nd && nd != rdir && nd != cdir) { + unsigned ndo = ((char *)nd) - data; + if (nd->type == NC_DIR) + for (unsigned i=0; i<DE(ndo)->pages; i++) { + struct nc_de_s *dd = IDE(nd, i); + if (dd->type) + _delKey(data+dd->name, nd, FALSE); + nd = DE(ndo); + } + sb->modtime++; + freeChunk(nd->offset); + freeChunk(DE(ndo)->name); + nd = DE(ndo); + struct nc_de_s *parent = DE(nd->parent); + memset(nd, 0, sizeof(struct nc_de_s)); + // keep parent directory sorted + if (tosort) { + unsigned i = 0; + while (i < parent->pages && IDE(parent, i) != nd) + i++; + memmove(((unsigned *)(data+parent->offset))+i, + ((unsigned *)(data+parent->offset))+i+1, + sizeof(unsigned)*(parent->pages-i-1)); + ((unsigned *)(data+parent->offset))[parent->pages-1] = ndo; + } + } + unLockFile(); +} + +int NConfig::_setKey(const char *name, const unsigned t, const char *value, const unsigned len) +{ + if (fd < 0) + return NC_ERR_NFILE; + if (omode != NC_O_RW) + return NC_ERR_RDONLY; + lockFile(NC_L_RW); + struct nc_de_s *nd = getDirEnt(name); +#ifdef NC_DEBUG_INSERT + fprintf(stderr, "Found DE %p\n", nd); +#endif + if (!nd) { + struct nc_de_s *sd = *name == '/' ? rdir : cdir; + char *parse = canonize(name), *p = parse; + + while ((nd = getDirEnt(p, sd))) + if (nd->type == NC_DIR) { + sd = nd; + p += strlen(p)+1; + } else { + free(parse); + unLockFile(); + return NC_ERR_PERM; + } + + size_t pl = 0; + struct nc_de_s ds; + unsigned sdo = ((char *)sd) - data; + while (*(p+(pl = strlen(p)+1))) { + ds.pages = ds.offset = 0; + ds.name = getChunk(pl); + memcpy(data+ds.name, p, pl); + ds.type = NC_DIR; +#ifdef NC_DEBUG_INSERT + fprintf(stderr, "Insertion parent 2: %p\n", DE(sdo)); +#endif + // FIXME: crc calculation + sdo = ((char *)insert(sdo, &ds)) - data; + p += pl; + } + ds.type = t; + memcpy(data+(ds.name = getChunk(pl)), p, pl); + ds.pages = ds.offset = 0; +#ifdef NC_DEBUG_INSERT + fprintf(stderr, "Insertion parent 1: %p\n", DE(sdo)); +#endif + nd = insert(sdo, &ds); + sb->modtime++; + free(parse); + } else + if (nd->type != t) { + unLockFile(); + return NC_ERR_TYPE; + } + unsigned ndo = ((char *)nd) - data; + if (t != NC_DIR) { + if (value) { + if (nd->offset && CS(nd->offset)-sizeof(unsigned) < len) { + freeChunk(nd->offset); + nd = DE(ndo); + nd->offset = 0; + } + if (nd->offset) { + if (CS(nd->offset)-sizeof(unsigned) > alignSize(len)+sizeof(unsigned)) { + unsigned trim = CS(nd->offset) - alignSize(len) - sizeof(unsigned); + unsigned off = nd->offset + alignSize(len) + sizeof(unsigned); + CS(off) = trim; + CS(nd->offset) -= trim; + freeChunk(off); + nd = DE(ndo); + } + } else { + unsigned off = getChunk(len); + nd = DE(ndo); + nd->offset = off; + } + memcpy(data+nd->offset, value, len); + nd->pages = len; + } else + if (nd->offset) { + freeChunk(nd->offset); + DE(ndo)->offset = 0; + } + } else + // Preallocate pages for directory + if (len > nd->pages) { + unsigned off = getChunk(sizeof(unsigned)*len); + if (DE(ndo)->offset) { + memcpy(data+off, data+DE(ndo)->offset, sizeof(unsigned)*(DE(ndo)->pages)); + freeChunk(DE(ndo)->offset); + } + DE(ndo)->offset = off; + for (unsigned al = len - DE(ndo)->pages; al; al--) { + off = getChunk(sizeof(struct nc_de_s)); + ((unsigned *)(data+DE(ndo)->offset))[DE(ndo)->pages++] = off; + } + } + unLockFile(); +#ifdef NC_DEBUG_INSERT + fprintf(stderr, "%p\n", cdir); +#endif + return NC_ERR_OK; +} + +char *NConfig::getName(const struct nc_de_s *w) +{ + if (w == rdir) + return strdup("/"); + char *parent = getName(DE(w->parent)); + unsigned l1 = strlen(parent); + unsigned l2 = strlen(data+w->name)+1; + + parent = (char *) realloc(parent, l1 + l2 + (l1 == 1 ? 0 : 1)); + if (l1 != 1) { + memcpy(parent+l1, "/", 2); + l1++; + } + memcpy(parent+l1, data+w->name, l2); + return parent; +} + +int NConfig::chDir(const char *name) +{ + if (fd < 0) + return NC_ERR_NFILE; + lockFile(NC_L_RO); + + int ret = NC_ERR_OK; + struct nc_de_s *nd = getDirEnt(name); + if (nd) { + if (nd->type == NC_DIR) { + cdir = nd; + free(cname); + cname = getName(cdir); + } else + ret = NC_ERR_NDIR; + } else + ret = NC_ERR_NEXIST; + unLockFile(); + return ret; +} + +const char *NConfig::pwDir() +{ + if (fd < 0) + return NULL; + lockFile(NC_L_RO); + struct nc_de_s *l = cdir; + char * ret = strdup(data+l->name); + while (DE(l->parent) != l) { + unsigned len = CS(l->name); + char *r = (char *) malloc(strlen(ret) + len + 2); + memcpy(r, data+l->name, len); + if (*ret != '/' && DE(l->parent) != rdir) + strcat(r, "/"); + strcat(r, ret); + free(ret); + ret = r; + l = DE(l->parent); + } + unLockFile(); + return ret; +} + +struct nc_de_s *NConfig::getDirEnt(const char *name, struct nc_de_s *cc) +{ + struct nc_de_s *ret = cc ? cc : ((*name == '/') ? rdir : cdir); + char *c = canonize(name), *can; + + if (!(can = c)) + return ret; + while (*c) { + if (!strcmp(c, "..")) + ret = DE(ret->parent); + else + if (strcmp(c, ".")) { + struct nc_de_s *re = ret; + int left = 0, right = ret->pages-1, p, r; + + ret = NULL; + while (left <= right) { + p = (left + right) / 2; + r = strcmp(c, data+IDE(re, p)->name); + if (r < 0) { + left = p + 1; + continue; + } + if (!r) { + ret = IDE(re, p); + break; + } + right = p - 1; + } + } + c += strlen(c)+1; + if (!ret || (*c && ret->type != NC_DIR)) { + ret = NULL; + break; + } + } + free(can); + return ret; +} + +char *NConfig::canonize(const char *name) +{ + if (*name == '/') + name++; + size_t i = strlen(name); + char *ret = (char *)calloc(1, i+3); + memcpy(ret, name, i); + for (size_t j=0; j<i; j++) + if (ret[j] == '/') + ret[j] = 0; + return ret; +} + +struct nc_de_s *NConfig::insert(unsigned where, struct nc_de_s *what) +{ +#ifdef NC_DEBUG_INSERT + fprintf(stderr, "Insertion: %s %d\n", data+what->name, what->type); +#endif + struct nc_de_s *w = DE(where); + if (!DE(where)->offset || IDE(w, w->pages-1)->type) { + unsigned a = getChunk((w->pages+sb->ent_inc)*sizeof(unsigned)); + w = DE(where); + if (w->offset) { + memcpy(data+a, data+w->offset, w->pages*sizeof(unsigned)); + freeChunk(w->offset); + w = DE(where); + } + w->offset = a; + for (unsigned ha = 0; ha<sb->ent_inc; ha++) { + unsigned off = getChunk(sizeof(struct nc_de_s)); + w = DE(where); + ((unsigned *)(data+w->offset))[w->pages] = off; + w->pages++; + } + } + int i = 0, l = 0, r = w->pages - 1, c; + while (l <= r) { + c = (l + r) / 2; + if (!IDE(w, c)->type || strcmp(data+what->name, data+IDE(w, c)->name) > 0) { + i = c; + r = c - 1; + } else + l = c + 1; + } + +#ifdef NC_DEBUG_INSERT + fprintf(stderr, "Insertion to slot %u (%s)\n", i, data+what->name); +#endif + what->parent = where; + unsigned to = ((unsigned *)(data+w->offset))[w->pages-1]; + memmove(((unsigned *)(data+w->offset))+i+1, ((unsigned *)(data+w->offset))+i, sizeof(unsigned)*(w->pages-i-1)); + ((unsigned *)(data+w->offset))[i] = to; + void *ret = memcpy(DE(to), what, sizeof(struct nc_de_s)); + sb->modtime++; + return (struct nc_de_s *)ret; +} + +void NConfig::status() +{ + if (fd < 0) + return; + lockFile(NC_L_RO); + fprintf(stderr, "Size:\t%u\n", sb->size); + unsigned low=0, hi=chunks[0].size, cnt=0, ttl=0; + for (unsigned i=0; i<sb->chunk_ttl; i++) + if (chunks[i].size > 0) { + if (!low || low > chunks[i].size) + low = chunks[i].size; + ttl += chunks[i].size; + cnt++; + } + unLockFile(); + fprintf(stderr, "Free:\t%u in %u chunk%s\n", ttl, cnt, cnt > 1 ? "s" : ""); + if (cnt > 0) + fprintf(stderr, "Min:\t%u\nAvg:\t%u\nMax:\t%u\n", low, ttl / cnt, hi); +} + +struct nc_ls_s *NConfig::ls(const char *name) +{ + if (fd < 0) + return NULL; + lockFile(NC_L_RO); + + struct nc_ls_s *rt = NULL; + unsigned count = 0; + struct nc_de_s *de = NULL; + struct nc_de_s *ds = name ? getDirEnt(name) : cdir; + + if (ds && ds->type == NC_DIR) { + for (unsigned i=0; i<ds->pages; i++) { + de = IDE(ds, i); + if (de->type && de->name) { + rt = (struct nc_ls_s *) realloc(rt, (count+2)*sizeof(nc_ls_s)); + rt[count].type = de->type; + rt[count].name = strdup(data+de->name); + rt[++count].type = 0; + rt[count].name = NULL; + } + } + } + unLockFile(); + return rt; +} + +void NConfig::fast_free(unsigned offset) +{ + unsigned s = CS(offset), i = 0; + offset -= sizeof(unsigned); + + while (1) { + if (!chunks[i].size) { +#ifdef NC_DEBUG_ALLOC + fprintf(stderr, "Inserting %u:%u to %u\n", offset, s, i); +#endif + chunks[i].offset = offset; + chunks[i].size = s; + break; + } + if (chunks[i].offset == offset + s) { +#ifdef NC_DEBUG_ALLOC + fprintf(stderr, "Prepending %u:%u to %u (%u:%u)\n", offset, s, i, chunks[i].offset, chunks[i].size); +#endif + chunks[i].offset -= s; + chunks[i].size += s; + break; + } + if (offset == chunks[i].offset + chunks[i].size) { +#ifdef NC_DEBUG_ALLOC + fprintf(stderr, "Appending %u:%u to %u (%u:%u)\n", offset, s, i, chunks[i].offset, chunks[i].size); +#endif + chunks[i].size += s; + break; + } + i++; + } + + // Keep the array sorted + while (i && chunks[i].size > chunks[i-1].size) { + unsigned b = chunks[i].size; + unsigned j = i - 1; + chunks[i].size = chunks[j].size; + chunks[j].size = b; + b = chunks[i].offset; + chunks[i].offset = chunks[j].offset; + chunks[j].offset = b; + i = j; + } +} + +int NConfig::renameKey(const char *oldname, const char *newname) +{ + if (fd < 0) + return NC_ERR_NFILE; + if (omode != NC_O_RW) + return NC_ERR_RDONLY; + lockFile(NC_L_RW); + int ret = NC_ERR_OK; + struct nc_de_s *parent, *nd = getDirEnt(newname); + if (nd) { + if ((nd = getDirEnt(oldname))) { + size_t len = strlen(newname)+1; + int inc = strcmp(oldname, newname); + unsigned i, off, pos, ndo = ((char *)nd) - data; + if (alignSize(len) != CS(nd->name)) { + freeChunk(nd->name); + off = getChunk(len); + DE(ndo)->name = off; + nd = DE(ndo); + } + memcpy(data+nd->name, newname, len); + parent = DE(nd->parent); + for (pos = 0; pos < parent->pages && IDE(parent, pos) != nd; pos++) + ; + for (i = pos; i>=0 && i<parent->pages; i += inc) + if (strcmp(data+IDE(parent, i)->name, newname) != inc) + break; + if (inc == -1) + memmove(((unsigned *)(data+parent->offset))+i+1, + ((unsigned *)(data+parent->offset))+i, + sizeof(unsigned)*(pos - i)); + else + memmove(((unsigned *)(data+parent->offset))+pos, + ((unsigned *)(data+parent->offset))+pos+1, + sizeof(unsigned)*(i-pos)); + ((unsigned *)(data+parent->offset))[i] = ndo; + sb->modtime++; + } else + ret = NC_ERR_NEXIST; + } else + ret = NC_ERR_PERM; + unLockFile(); + return NC_ERR_OK; +} + +int NConfig::createDir(const char *name, unsigned entries) +{ + return _setKey(name, NC_DIR, NULL, entries); +} + +int NConfig::setKey(const char *name, const unsigned long long value) +{ + return _setKey(name, NC_UINT, (const char *)&value, sizeof(value)); +} + +int NConfig::setKey(const char *name, const unsigned value) +{ + unsigned long long b = value; + return _setKey(name, NC_UINT, (const char *)&b, sizeof(b)); +} + +int NConfig::setKey(const char *name, const signed long long value) +{ + return _setKey(name, NC_INT, (const char *)&value, sizeof(value)); +} + +int NConfig::setKey(const char *name, const int value) +{ + signed long long b = value; + return _setKey(name, NC_INT, (const char *)&b, sizeof(b)); +} + +int NConfig::setKey(const char *name, const char *value) +{ + return _setKey(name, NC_STRING, value, strlen(value)+1); +} + +int NConfig::setKey(const char *name, const long double value) +{ + return _setKey(name, NC_DOUBLE, (const char *)&value, sizeof(value)); +} + +int NConfig::setKey(const char *name, const double value) +{ + long double b = value; + return _setKey(name, NC_DOUBLE, (const char *)&b, sizeof(b)); +} + +int NConfig::setKey(const char *name, const char *value, const unsigned len) +{ + if (!value && len) + return NC_ERR_NVAL; + if (!len) + return _setKey(name, NC_RAW, NULL, 0); + return _setKey(name, NC_RAW, value, len); +} + +int NConfig::getKey(const char *name, unsigned long long &value) +{ + if (fd < 0) + return NC_ERR_NFILE; + lockFile(NC_L_RO); + int ret = NC_ERR_OK; + struct nc_de_s *k = getDirEnt(name); + if (k) { + if (k->type == NC_UINT) { + memcpy(&value, data+k->offset, sizeof(value)); + } else + ret = NC_ERR_TYPE; + } else + ret = NC_ERR_NEXIST; + unLockFile(); + return ret; +} + +int NConfig::getKey(const char *name, unsigned &value) +{ + if (fd < 0) + return NC_ERR_NFILE; + lockFile(NC_L_RO); + int ret = NC_ERR_OK; + struct nc_de_s *k = getDirEnt(name); + if (k) { + if (k->type == NC_UINT) { + unsigned long long b; + memcpy(&b, data+k->offset, sizeof(b)); + value = b; + } else + ret = NC_ERR_TYPE; + } else + ret = NC_ERR_NEXIST; + unLockFile(); + return ret; +} + +int NConfig::getKey(const char *name, long double &value) +{ + if (fd < 0) + return NC_ERR_NFILE; + lockFile(NC_L_RO); + int ret = NC_ERR_OK; + struct nc_de_s *k = getDirEnt(name); + if (k) { + if (k->type == NC_DOUBLE) { + memcpy(&value, data+k->offset, sizeof(value)); + } else + ret = NC_ERR_TYPE; + } else + ret = NC_ERR_NEXIST; + unLockFile(); + return ret; +} + +int NConfig::getKey(const char *name, double &value) +{ + if (fd < 0) + return NC_ERR_NFILE; + lockFile(NC_L_RO); + int ret = NC_ERR_OK; + struct nc_de_s *k = getDirEnt(name); + if (k) { + if (k->type == NC_DOUBLE) { + long double b; + memcpy(&b, data+k->offset, sizeof(b)); + value = b; + } else + ret = NC_ERR_TYPE; + } else + ret = NC_ERR_NEXIST; + unLockFile(); + return ret; +} + +int NConfig::getKey(const char *name, signed long long &value) +{ + if (fd < 0) + return NC_ERR_NFILE; + lockFile(NC_L_RO); + int ret = NC_ERR_OK; + struct nc_de_s *k = getDirEnt(name); + if (k) { + if (k->type == NC_INT) { + memcpy(&value, data+k->offset, sizeof(value)); + } else + ret = NC_ERR_TYPE; + } else + ret = NC_ERR_NEXIST; + unLockFile(); + return ret; +} + +int NConfig::getKey(const char *name, int &value) +{ + if (fd < 0) + return NC_ERR_NFILE; + lockFile(NC_L_RO); + int ret = NC_ERR_OK; + struct nc_de_s *k = getDirEnt(name); + if (k) { + if (k->type == NC_INT) { + signed long long b; + memcpy(&b, data+k->offset, sizeof(b)); + value = b; + } else + ret = NC_ERR_TYPE; + } else + ret = NC_ERR_NEXIST; + unLockFile(); + return ret; +} + +int NConfig::getKey(const char *name, char *&value) +{ + if (fd < 0) + return NC_ERR_NFILE; + lockFile(NC_L_RO); + int ret = NC_ERR_OK; + struct nc_de_s *k = getDirEnt(name); + if (k) { + if (k->type == NC_STRING) { + if (k->offset) { + if (!(value = strdup(data+k->offset))) + ret = NC_ERR_NMEM; + } else + value = NULL; + } else + ret = NC_ERR_TYPE; + } else + ret = NC_ERR_NEXIST; + unLockFile(); + return ret; +} + +int NConfig::getKey(const char *name, char *&value, unsigned &len) +{ + if (fd < 0) + return NC_ERR_NFILE; + lockFile(NC_L_RO); + int ret = NC_ERR_OK; + struct nc_de_s *k = getDirEnt(name); + if (k) { + if (k->type == NC_RAW) { + if (k->offset) { + len = k->pages; + value = (char *)malloc(len); + memcpy(value, data+k->offset, len); + } else { + len = 0; + value = NULL; + } + } else + ret = NC_ERR_TYPE; + } else + ret = NC_ERR_NEXIST; + unLockFile(); + return ret; +} + +void NConfig::lockFile(int type, int force) +{ +#ifdef NC_DEBUG_LOCK + fprintf(stderr, "Lock called type=%d force=%d lock=%d olck=%u\n", type, force, lock, olck); +#endif + if (lock == NC_L_RO && type == NC_L_RW) { + fprintf(stderr, "Lock promotion is not possible.\n"); + abort(); + } + if (lock != NC_L_NONE) { + olck++; + return; + } + + struct flock flc = { type == NC_L_RW ? F_WRLCK : F_RDLCK, SEEK_SET, 0, 0, 0 }; + while (fcntl(fd, F_SETLKW, &flc)) { + sched_yield(); + flc.l_type = type == NC_L_RW ? F_WRLCK : F_RDLCK; + flc.l_whence = SEEK_SET; + flc.l_len = flc.l_start = 0; + } + +#ifdef NC_DEBUG_LOCK + fprintf(stderr, "Locked %u %u %s\n", sb->modtime, update, force ? "forced." : ""); +#endif + if (careful && type == NC_L_RW) + mprotect(data, sb->size, PROT_READ | PROT_WRITE); + lock = type; + olck = 0; + if (sb->modtime != update || force) { + // refresh memory mapping + if (lsize != sb->size) { + _remap(lsize, sb->size); + lsize = sb->size; + chunks = CM(sb->chunk); + } + cdir = getDirEnt(cname); + update = sb->modtime; + } +} + +void NConfig::unLockFile() +{ +#ifdef NC_DEBUG_LOCK + fprintf(stderr, "UnLock called lock=%u olck=%u\n", lock, olck); +#endif + if (olck) { + olck--; + return; + } + if (lock == NC_L_NONE) + return; + struct flock flc = {F_UNLCK, SEEK_SET, 0, 0, 0 }; + update = sb->modtime; +#ifdef NC_DEBUG_LOCK + fprintf(stderr, "Unlock %u\n", update); +#endif + if (careful) + mprotect(data, sb->size, PROT_READ); + fcntl(fd, F_SETLK, &flc); + lock = NC_L_NONE; + olck = 0; +} + +void NConfig::_remap(const size_t osize, const size_t nsize) +{ + data = (char *) mremap(data, osize, nsize, 1); + if (data == MAP_FAILED) { + perror("mremap"); + abort(); + } + sb = SB; + rdir = DE(sb->root); +} + +char * NConfig::version() +{ + return strdup("EliteDVB registry"); +} + diff --git a/lib/base/nconfig.h b/lib/base/nconfig.h new file mode 100644 index 00000000..12a3c6c4 --- /dev/null +++ b/lib/base/nconfig.h @@ -0,0 +1,392 @@ +#ifndef NC_NCONFIG_H +#define NC_NCONFIG_H 1 + +#include <stdio.h> +#include <stdlib.h> + +/* + * Superblock definitions + */ +#define NC_SB_MAGIC ("\0\11\22") // Superblock identifier + +/* + * Key type definitions + */ +#define NC_DIR 0x01 // The key is a directory +#define NC_STRING 0x02 // The key contains a string +#define NC_INT 0x03 // The key contains a signed integer +#define NC_UINT 0x04 // The key contains an unsigned integer +#define NC_RAW 0x05 // The key contains raw data +#define NC_DOUBLE 0x06 // The key contains a double +#define NC_LINK 0x07 // The key points somewhere else + +/* + * File access definitions + */ +#define NC_O_RO 0x01 // Open file in read-only mode +#define NC_O_RW 0x02 // Open file in read-write mode + +/* + * Lock types + */ +#define NC_L_NONE 0x00 // No lock +#define NC_L_RO 0x01 // Read-only lock +#define NC_L_RW 0x02 // Read-write lock + +/* + * Error codes + */ +#define NC_ERR_OK 0 // Everything is OK +#define NC_ERR_TYPE -1 // Type mismatch +#define NC_ERR_NDIR -2 // Key is not a directory +#define NC_ERR_PERM -3 // Operation is not allowed +#define NC_ERR_NMEM -4 // Not enough memory to complete operation +#define NC_ERR_NEXIST -5 // Key does not exist +#define NC_ERR_NFILE -6 // No file is assigned/open +#define NC_ERR_CORRUPT -7 // File is corrupted +#define NC_ERR_NVAL -8 // Invalid value +#define NC_ERR_RDONLY -9 // File is open in read-only mode +#define NC_ERR_NOSUPPORT -10 // Support is not compiled-in + +/* + * Truth value definitions + */ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* + * Header of the config file. + */ +struct nc_sb_s { + char magic[4]; // superblock magic + unsigned size; // Current file size + unsigned ent_inc; // directory increment + unsigned chunk_inc; // Memory chunks increment + unsigned size_inc; // file size increment + unsigned chunk_ttl; // size of chunkmap + unsigned chunk; // pointer to chunkmap + unsigned root; // pointer to root direntry + unsigned modtime; // file version +}; + +/* + * Free chunk descriptor + */ +struct nc_chunk_s { + unsigned offset; + unsigned size; +}; + +/* + * In-file directory entry + */ +struct nc_de_s { + unsigned name; + unsigned type; + unsigned parent; + unsigned offset; + unsigned pages; + unsigned crc; +}; + +/* + * Ls reporting + */ +struct nc_ls_s { + const char *name; + unsigned type; +}; + +class NConfig +{ +public: + /* + * Class constructor + * pass TRUE as parameter to enable + * write protection when leaving library + */ + NConfig(int protect = FALSE); + virtual ~NConfig(); + + /* + * Set file name (prior to open) + * Errors: + * NC_ERR_PERM file is already open + * NC_ERR_NVAL no file name is given + */ + int setName(const char *name); + + /* + * Open the configuration file, re-open it + * Errors: + * NC_ERR_NFILE no file name is assigned + * NC_ERR_TYPE file open mode is invalid + * NC_ERR_PERM file cannot be opened/created + * NC_ERR_NMEM unable to mmap the file + * NC_ERR_CORRUPT superblock magic mismatch + */ + int open(const int how = NC_O_RW); + + /* + * Close the configuration file + * No errors defined + */ + void close(); + + void flush(); // flush file if not mmap'ed + + /* + * Create a new file + * resize is filesize increment is system pages + * dirent is directory increment + * mchunks is memory block increment + * Errors: + * NC_ERR_PERM file already exists + * NC_ERR_NFILE cannot create new file + * NC_ERR_NVAL file is already open + */ + int createNew(unsigned resize = 4, unsigned dirent = 32, unsigned mchunks = 32); + + /* + * Get an unsigned integer + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_NEXIST the key does not exist + * NC_ERR_TYPE the key exists, but is of different type + */ + int getKey(const char *name, unsigned &value); + int getKey(const char *name, unsigned long long &value); + + /* + * Get a signed integer + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_NEXIST the key does not exist + * NC_ERR_TYPE the key exists, but is of different type + */ + int getKey(const char *name, int &value); + int getKey(const char *name, signed long long &value); + + /* + * Get a string + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_NEXIST the key does not exist + * NC_ERR_TYPE the key exists, but is of different type + */ + int getKey(const char *name, char *&value); + + /* + * Get a long double + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_NEXIST the key does not exist + * NC_ERR_TYPE the key exists, but is of different type + */ + int getKey(const char *name, double &value); + int getKey(const char *name, long double &value); + + /* + * Get raw data + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_NEXIST the key does not exist + * NC_ERR_TYPE the key exists, but is of different type + */ + int getKey(const char *name, char *&value, unsigned &len); + + /* + * Insert an unsigned integer + * NC_ERR_NFILE no file is open + * NC_ERR_RDONLY file is open in read-only mode + * NC_ERR_PERM intermediate key is not a directory + * NC_ERR_TYPE key already exists, but is not an usigned integer + * NC_ERR_NEXIST key does not exist (should NEVER happen) + */ + int setKey(const char *name, const unsigned value); + int setKey(const char *name, const unsigned long long value); + + /* + * Insert an integer + * NC_ERR_NFILE no file is open + * NC_ERR_RDONLY file is open in read-only mode + * NC_ERR_PERM intermediate key is not a directory + * NC_ERR_TYPE key already exists, but is not a signed integer + * NC_ERR_NEXIST key does not exist (should NEVER happen) + */ + int setKey(const char *name, const int value); + int setKey(const char *name, const signed long long value); + + /* + * Insert a string + * NC_ERR_NFILE no file is open + * NC_ERR_RDONLY file is open in read-only mode + * NC_ERR_PERM intermediate key is not a directory + * NC_ERR_TYPE key already exists, but is not a string + * NC_ERR_NEXIST key does not exist (should NEVER happen) + */ + int setKey(const char *name, const char *value); + + /* + * Insert raw data + * NC_ERR_NFILE no file is open + * NC_ERR_RDONLY file is open in read-only mode + * NC_ERR_PERM intermediate key is not a directory + * NC_ERR_TYPE key already exists, but is not raw data + * NC_ERR_NEXIST key does not exist (should NEVER happen) + */ + int setKey(const char *name, const char *value, const unsigned len); + + /* + * Insert a double + * NC_ERR_NFILE no file is open + * NC_ERR_RDONLY file is open in read-only mode + * NC_ERR_PERM intermediate key is not a directory + * NC_ERR_TYPE key already exists, but is not raw data + * NC_ERR_NEXIST key does not exist (should NEVER happen) + */ + int setKey(const char *name, const double value); + int setKey(const char *name, const long double value); + + /* + * Rename a key + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_RDONLY file is open read-only + * NC_ERR_NEXIST the key does not exist + * NC_ERR_PERM key with specified name already exists + */ + int renameKey(const char *oldname, const char *newname); + + /* + * Delete a key + * No errors defined + */ + void delKey(const char *name); + + /* + * Create a directory + * entries parameter specifies number of direntries to preallocate + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_RDONLY file is open in read-only mode + * NC_ERR_PERM intermediate key is not a directory + * NC_ERR_TYPE key already exists, but is not a directory + * NC_ERR_NEXIST key does not exist (should NEVER happen) + */ + int createDir(const char *name, unsigned entries = 0); + + /* + * Change working directory + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_NDIR target key is not a directory + * NC_ERR_NEXIST target key direcotry does not exist + */ + int chDir(const char *name); + + /* + * Print working directory + * Errors: + * Returns NULL on error + */ + const char *pwDir(); + + /* + * List all keys in current/specified directory + * Result is a NULL-terminated array of nc_ls_s + * structures. + * Errors: + * Returns NULL on error + * Note: + * You need to free the returned pointer, + * as well as all the names in it. + */ + struct nc_ls_s *ls(const char *dir = NULL); + + /* + * Lock file + * This will block until lock becomes available + * type is either: + * NC_L_RO for read-only lock + * NC_L_RW for read-write lock + * No errors defined + * + * NOTE: lock may get promoted + */ + void lockFile(int type, int force = FALSE); + + /* + * Unlock file + * No errors defined + */ + void unLockFile(); + + /* + * Print out (to stderr) information about current file + * No errors defined + */ + void status(); + + /* + * Return version string + */ + static char *version(); + + /* + * Dump current file to XML + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_PERM could not write XML output + */ + int toXML(const char *filename); + + /* + * Load XML to current file + * a file has to be open + * force can be + * TRUE - existing keys will be deleted + * FALSE - import will ignore a key if existing key type conflicts + * Errors: + * NC_ERR_NFILE no file is open + * NC_ERR_PERM file is open read-only + */ + int fromXML(const char *filename, int force = TRUE); + +protected: + int fd, omode, lock, careful; + char *fname, *data, *cname; + unsigned lsize, update; + unsigned revision, olck; + struct nc_sb_s *sb; + struct nc_de_s *rdir, *cdir; + struct nc_chunk_s *chunks; + + int _setKey(const char *, const unsigned, const char *, const unsigned); + void _delKey(const char *, struct nc_de_s *, int); + void expand(unsigned); + + void fast_free(unsigned); + + unsigned getChunk(unsigned); + void freeChunk(unsigned); + static inline unsigned alignSize(unsigned); + + struct nc_de_s *getDirEnt(const char *, struct nc_de_s * = NULL); + struct nc_de_s *insert(unsigned, struct nc_de_s *); + char *canonize(const char *); + char *getName(const struct nc_de_s *); + + void _remap(const size_t, const size_t); + + inline unsigned crc(const char *, unsigned); + void store(nc_de_s *, FILE *); + void restore(void *, int); +}; + +#endif /* NC_NCONFIG_H */ + diff --git a/lib/base/nxml.cpp b/lib/base/nxml.cpp new file mode 100644 index 00000000..f32880a6 --- /dev/null +++ b/lib/base/nxml.cpp @@ -0,0 +1,339 @@ +#include <lib/base/nconfig.h> +#include <string.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_TIME_H +#include <time.h> +#endif + +#ifdef HAVE_LIBXML2 +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/parserInternals.h> +#else +#define xmlChar char +#endif /* HAVE_LIBXML2 */ + +#define DE(x) ((struct nc_de_s *) (data+(x))) +#define IDE(x, y) (DE(((unsigned *) (data+(x)->offset))[(y)])) +#define XML_DE ((const xmlChar *) "dirEntry") +#define XML_NS ((const xmlChar *) "http://hq.alert.sk/projects/nconfig") +#define XML_ROOT ((const xmlChar *) "NConfigExport") + +static char *encodeXml(const char *what) +{ + unsigned p = 0, size = 6*strlen(what)+1; + char *ret = (char *)malloc(size); + for (; *what; what++) { + switch (*what) { + case '"': + ret[p++] = '&'; + ret[p++] = 'q'; + ret[p++] = 'u'; + ret[p++] = 'o'; + ret[p++] = 't'; + ret[p++] = ';'; + continue; + case '>': + ret[p++] = '&'; + ret[p++] = 'q'; + ret[p++] = 't'; + ret[p++] = ';'; + continue; + case '<': + ret[p++] = '&'; + ret[p++] = 'l'; + ret[p++] = 't'; + ret[p++] = ';'; + continue; + case '&': + ret[p++] = '&'; + ret[p++] = 'a'; + ret[p++] = 'm'; + ret[p++] = 'p'; + ret[p++] = ';'; + continue; + } + if (*what >= 0x20 || *what == '\n' || *what == '\r' || *what == '\t') + ret[p++] = *what; + else + p += sprintf(ret+p, "&#%d;", *what); + } + ret[p] = '\0'; + return ret; +} + +void NConfig::store(nc_de_s *de, FILE *f) +{ + struct nc_de_s *cc; + for (unsigned i=0; i<de->pages; i++) + if ((cc = IDE(de, i))->type) { + char *encname = encodeXml(data+cc->name); + fprintf(f, "<nc:%s name=\"%s\" type=\"%d\" value=\"", XML_DE, encname, cc->type); + free(encname); + switch (cc->type) { + case NC_DIR: + fprintf(f, "%u\">\n", cc->pages); + store(cc, f); + fprintf(f, "</nc:%s>\n", XML_DE); + break; + case NC_STRING: + fprintf(f, "%s\"/>\n", encname = encodeXml(data+cc->offset)); + free(encname); + break; + case NC_INT: + fprintf(f, "%lld\"/>\n", *((signed long long *) (data+cc->offset))); + break; + case NC_UINT: + fprintf(f, "%llu\"/>\n", *((unsigned long long *) (data+cc->offset))); + break; + case NC_DOUBLE: + fprintf(f, "%La\"/>\n", *((long double *) (data+cc->offset))); + break; + case NC_RAW: + { + const char *raw = data+cc->offset; + for (unsigned j=0; j<cc->pages; j++) + fprintf(f, "%d%d%d", raw[j] / 100, (raw[j] % 100) / 10, raw[j] % 10); + fprintf(f, "\"/>\n"); + } + } + } +} + +int NConfig::toXML(const char *filename) +{ + if (fd < 0) + return NC_ERR_NFILE; + + FILE *f = fopen(filename, "w"); + if (!f) + return NC_ERR_PERM; + + fprintf(f, "%s", "<?xml version=\"1.0\"?>\n"); + fprintf(f, "<nc:%s xmlns:nc=\"%s\" libVersion=\"%s\"", XML_ROOT, XML_NS, VERSION); +#ifdef HAVE_TIME_H + time_t t = time(NULL); + char *tim = ctime(&t); + tim[strlen(tim)-1] = 0; + fprintf(f, " time=\"%s\"", tim); +#endif /* HAVE_TIME_H */ + fprintf(f, ">\n"); + lockFile(NC_L_RO); + + store(rdir, f); + + unLockFile(); + fprintf(f, "</nc:%s>\n", XML_ROOT); + fclose(f); + return NC_ERR_OK; +} + +#ifdef HAVE_LIBXML2 +static xmlSAXHandler sh; +enum stateEnum {noRoot = 0, inRoot, inDir, inEnt, unknown}; + +struct ncParseState { + stateEnum state, pState; + xmlChar *ns; + unsigned depth; + unsigned unDepth; + unsigned force; + NConfig *which; +}; + +static int ncXmlSAXParseFile(xmlSAXHandlerPtr sax, void *user_data, const char *filename) +{ + int ret = 0; + xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename); + if (!ctxt) + return -1; + ctxt->sax = sax; + ctxt->userData = user_data; + xmlParseDocument(ctxt); + ret = ctxt->wellFormed ? 0 : -1; + if (sax) + ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + return ret; +} + +static xmlEntityPtr ncXmlGetEntity(void *user_data, const CHAR *name) +{ + return xmlGetPredefinedEntity(name); +} + +static void ncXmlStartElement(void *user_data, const CHAR *name, const CHAR **attrs) +{ + struct ncParseState *p = (struct ncParseState *)user_data; +#ifdef NC_DEBUG_XML + fprintf(stderr, "New element %s state=%d %s\n", name, p->state, p->ns); +#endif + if (p->state == unknown) { + p->unDepth++; + return; + } + if (p->state == noRoot) { + while (*attrs) { + if (!xmlStrncmp(*attrs, (const xmlChar *) "xmlns:", 6)) { + if (!xmlStrcmp(attrs[1], XML_NS)) { + p->ns = xmlStrdup((*attrs)+6); + break; + } + } + attrs += 2; + } + char *b = (char *) malloc(xmlStrlen(p->ns)+xmlStrlen(XML_ROOT)+2); + sprintf(b, "%s:%s", p->ns, XML_ROOT); + if (xmlStrcmp(name, (xmlChar *)b)) { +#ifdef NC_DEBUG_XML + fprintf(stderr, "NewElement, entering unknown %s\n", name); +#endif + p->pState = p->state; + p->state = unknown; + } else + p->state = inRoot; + free(b); + return; + } + if (p->state == inRoot || p->state == inDir) { + const xmlChar *value = NULL, *n = NULL; + int type = 0; + while (*attrs) { + if (!xmlStrcmp(*attrs, (const xmlChar *)"value")) + value = attrs[1]; + if (!xmlStrcmp(*attrs, (const xmlChar *)"name")) + n = attrs[1]; + if (!xmlStrcmp(*attrs, (const xmlChar *)"type")) + type = atoi(attrs[1]); + attrs += 2; + } +#ifdef NC_DEBUG_XML + fprintf(stderr, "%s %s %s %d %d\n", name, n, value, type, p->state); +#endif + char *b = (char *) malloc(xmlStrlen(p->ns)+xmlStrlen(XML_DE)+2); + sprintf(b, "%s:%s", p->ns, XML_DE); + if (xmlStrcmp(name, (xmlChar *)b) || !type || !value || !n) { +#ifdef NC_DEBUG_XML + fprintf(stderr, "NewElement, entering unknown on mismatch\n"); +#endif + p->pState = p->state; + p->state = unknown; + free(b); + return; + } + free(b); + if (p->force) + p->which->delKey((const char *)n); + + switch (type) { + case NC_DIR: + if (p->which->createDir((const char *)n, strtoul((const char *)value, NULL, 0)) != NC_ERR_OK) { + p->pState = p->state; + p->state = unknown; +#ifdef NC_DEBUG_XML + fprintf(stderr, "NewElement, entering unknown on failed mkdir\n"); +#endif + return; + } + p->which->chDir((const char *)n); + break; + case NC_STRING: + p->which->setKey((const char *)n, (const char *)value); + break; + case NC_INT: + p->which->setKey((const char *)n, strtoll((const char *)value, NULL, 0)); + break; + case NC_UINT: + p->which->setKey((const char *)n, strtoull((const char *)value, NULL, 0)); + break; + case NC_DOUBLE: + { + long double c; + sscanf((const char *)value, "%La", &c); + p->which->setKey((const char *)n, c); + } + break; + case NC_RAW: + { + unsigned size = xmlStrlen(value) / 3; + char *dec = NULL; + if (size) { + dec = (char *)malloc(size); + for (unsigned i=0, k=0; i<size; i++, k += 3) + dec[i] = value[k] * 100 + value[k+1] * 10 + value[k+2]; + } + p->which->setKey((const char *)n, dec, size); + free(dec); + } + } + if (type == NC_DIR) { + p->state = inDir; + p->depth++; + } else { + p->pState = p->state; + p->state = inEnt; + } + return; + } +} + +static void ncXmlEndElement(void *user_data, const CHAR *name) +{ + struct ncParseState *p = (struct ncParseState *)user_data; +#ifdef NC_DEBUG_XML + fprintf(stderr, "EndElement %s %s %d\n", name, p->ns, p->state); +#endif + if (p->state == inEnt) { + p->state = p->pState; + return; + } + if (p->state == unknown) { + if (p->unDepth) + p->unDepth--; + else + p->state = p->pState; + return; + } + if (p->state == inRoot) { + p->state = noRoot; + free(p->ns); + p->ns = NULL; + return; + } + if (p->state == inDir) { + p->depth--; + if (!p->depth) + p->state = inRoot; + p->which->chDir(".."); + } +} +#endif /* HAVE_LIBXML2 */ + +int NConfig::fromXML(const char *filename, int force) +{ + if (fd < 0) + return NC_ERR_NFILE; + if (omode != NC_O_RW) + return NC_ERR_PERM; +#ifndef HAVE_LIBXML2 + return NC_ERR_NOSUPPORT; +#else + struct ncParseState state = { noRoot, noRoot, NULL, 0, 0, force, this }; + sh.getEntity = ncXmlGetEntity; + sh.startElement = ncXmlStartElement; + sh.endElement = ncXmlEndElement; + + lockFile(NC_L_RW); + cdir = rdir; + int ret = ncXmlSAXParseFile(&sh, &state, filename); + cdir = rdir; + unLockFile(); + + return ret < 0 ? NC_ERR_NVAL : NC_ERR_OK; +#endif /* HAVE_LIBXML2 */ +} + diff --git a/lib/base/object.h b/lib/base/object.h new file mode 100644 index 00000000..744bff19 --- /dev/null +++ b/lib/base/object.h @@ -0,0 +1,30 @@ +#ifndef __base_object_h +#define __base_object_h + +#include <assert.h> + +// #define OBJECT_DEBUG + +#include <lib/base/smartptr.h> +#ifdef OBJECT_DEBUG +#include <lib/base/eerror.h> +#endif + +typedef int RESULT; + +class iObject +{ +public: + virtual void AddRef()=0; + virtual void Release()=0; +}; + +#define DECLARE_REF private: int ref; public: void AddRef(); void Release(); +#ifdef OBJECT_DEBUG +extern int object_total_remaining; +#define DEFINE_REF(c) void c::AddRef() { ++object_total_remaining; ++ref; eDebug("OBJECT_DEBUG " #c "+%p now %d", this, ref); } void c::Release() { --object_total_remaining; eDebug("OBJECT_DEBUG " #c "-%p now %d", this, ref-1); if (!--ref) delete this; } +#else +#define DEFINE_REF(c) void c::AddRef() { ++ref; } void c::Release() { if (!--ref) delete this; } +#endif + +#endif diff --git a/lib/base/ringbuffer.h b/lib/base/ringbuffer.h new file mode 100644 index 00000000..f2cd9058 --- /dev/null +++ b/lib/base/ringbuffer.h @@ -0,0 +1,109 @@ +#ifndef QueueRingBufferH +#define QueueRingBufferH + +template <class T> +class queueRingBuffer +{ + template <class A> + struct link + { + link ( const A &val ) + :value(val) + {} + A value; + link *nextLink; + link *prevLink; + }; + + link<T> *lastFilled; + link<T> *lastFree; + unsigned int max; + int count; +public: + queueRingBuffer( unsigned int max ); + ~queueRingBuffer(); + int size() { return count; } + T& queueRingBuffer::dequeue(); + T& queueRingBuffer::current(); + void queueRingBuffer::enqueue( const T &val ); +}; + +template <class T> +queueRingBuffer<T>::queueRingBuffer( unsigned int max ) +{ + // constructor for queues based on ring buffers + // create the first link + T initialvalue; + lastFree = new link<T>( initialvalue ); + lastFilled = lastFree; + // make value point to itself + lastFilled->nextLink = lastFilled; + lastFilled->prevLink = lastFilled; + // now add the remainder of the elements + while ( max-- > 0 ) + { + link<T> * newLink = new link<T>( initialvalue ); + newLink->prevLink = lastFilled; + newLink->nextLink = lastFilled->nextLink; + lastFilled->nextLink->prevLink = newLink; + lastFilled->nextLink = newLink; + } +} + +template <class T> +queueRingBuffer<T>::~queueRingBuffer() +{ + // delete all memory associated with ring buffer + link<T> * p = lastFree; + link<T> * next; + + // walk around the circle deleting nodes + while( p->nextLink != lastFree ) + { + next = p->nextLink; + delete p; + p = next; + } +} + +template <class T> +T& queueRingBuffer<T>::dequeue() +{ + // remove element form front of queue + // advance last free position + lastFree = lastFree->nextLink; + count--; + // return value stored in last free position + return lastFree->value; +} + +template <class T> +T& queueRingBuffer<T>::current() +{ + // return value stored in current + return lastFree->nextLink->value; +} + +template <class T> +void queueRingBuffer<T>::enqueue( const T &val ) +{ + // add new element to end of queue buffer + // first check for potential overflow + if( lastFilled->nextLink == lastFree ) + { + eDebug("increase size %d", count); + link<T> * newLink = new link<T>( val ); + newLink->prevLink = lastFilled; + newLink->nextLink = lastFilled->nextLink; + lastFilled->nextLink->prevLink = newLink; + lastFilled->nextLink = newLink; + } + else + { + // simply advance the last filled pointer + lastFilled = lastFilled->nextLink; + lastFilled->value = val; + } + count++; +} +#endif diff --git a/lib/base/smartptr.cpp b/lib/base/smartptr.cpp new file mode 100644 index 00000000..95269d74 --- /dev/null +++ b/lib/base/smartptr.cpp @@ -0,0 +1,2 @@ +#include "smartptr.h" +#include <stdio.h> diff --git a/lib/base/smartptr.h b/lib/base/smartptr.h new file mode 100644 index 00000000..029fd1dc --- /dev/null +++ b/lib/base/smartptr.h @@ -0,0 +1,60 @@ +#ifndef __smartptr_h +#define __smartptr_h + +#include "object.h" +#include <stdio.h> + +template<class T> +class ePtr +{ +protected: + T *ptr; +public: + T &operator*() { return *ptr; } + ePtr(): ptr(0) + { + } + ePtr(T *c): ptr(c) + { + if (c) + c->AddRef(); + } + ePtr(const ePtr &c) + { + ptr=c.ptr; + if (ptr) + ptr->AddRef(); + } + ePtr &operator=(T *c) + { + if (ptr) + ptr->Release(); + ptr=c; + if (ptr) + ptr->AddRef(); + return *this; + } + + ePtr &operator=(ePtr<T> &c) + { + if (ptr) + ptr->Release(); + ptr=c.ptr; + if (ptr) + ptr->AddRef(); + return *this; + } + + ~ePtr() + { + if (ptr) + ptr->Release(); + } + T* &ptrref() { assert(!ptr); return ptr; } + T* operator->() { assert(ptr); return ptr; } + const T* operator->() const { assert(ptr); return ptr; } + operator T*() const { return this->ptr; } +}; + + +#endif diff --git a/lib/base/thread.cpp b/lib/base/thread.cpp new file mode 100644 index 00000000..4cff9259 --- /dev/null +++ b/lib/base/thread.cpp @@ -0,0 +1,34 @@ +#include <lib/base/thread.h> +#include <stdio.h> +#include <lib/base/eerror.h> + +void *eThread::wrapper(void *ptr) +{ + ((eThread*)ptr)->thread(); + pthread_exit(0); +} + +eThread::eThread() +{ + alive=0; +} + +void eThread::run() +{ + alive=1; + pthread_create(&the_thread, 0, wrapper, this); +} + +eThread::~eThread() +{ + if (alive) + kill(); +} + +void eThread::kill() +{ + alive=0; + eDebug("waiting for thread shutdown"); + pthread_join(the_thread, 0); + eDebug("ok"); +} diff --git a/lib/base/thread.h b/lib/base/thread.h new file mode 100644 index 00000000..56b74bed --- /dev/null +++ b/lib/base/thread.h @@ -0,0 +1,23 @@ +#ifndef __lib_base_thread_h +#define __lib_base_thread_h + +#include <pthread.h> + +class eThread +{ + pthread_t the_thread; + static void *wrapper(void *ptr); + int alive; +public: + bool thread_running() { return alive; } + eThread(); + virtual ~eThread(); + + void run(); + + virtual void thread()=0; + + void kill(); +}; + +#endif |
