From 342b273234405ab76dc159d2e402bfb1ddfa1d8f Mon Sep 17 00:00:00 2001 From: Pixel Date: Mon, 3 Oct 2011 14:48:05 -0700 Subject: First commit - very basic features. --- Makefile | 83 +++++++++++++++++++++++++++++++++++ includes/BString.h | 97 +++++++++++++++++++++++++++++++++++++++++ includes/Exceptions.h | 30 +++++++++++++ includes/Local.h | 37 ++++++++++++++++ includes/Main.h | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++ includes/Printer.h | 45 +++++++++++++++++++ src/BString.cc | 108 +++++++++++++++++++++++++++++++++++++++++++++ src/Local.cc | 27 ++++++++++++ src/Main.cc | 34 +++++++++++++++ src/Printer.cc | 60 +++++++++++++++++++++++++ tests/test-String.cc | 50 +++++++++++++++++++++ 11 files changed, 689 insertions(+) create mode 100644 Makefile create mode 100644 includes/BString.h create mode 100644 includes/Exceptions.h create mode 100644 includes/Local.h create mode 100644 includes/Main.h create mode 100644 includes/Printer.h create mode 100644 src/BString.cc create mode 100644 src/Local.cc create mode 100644 src/Main.cc create mode 100644 src/Printer.cc create mode 100644 tests/test-String.cc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..319997f --- /dev/null +++ b/Makefile @@ -0,0 +1,83 @@ +ifeq ($(SYSTEM),) + SYSTEM = $(shell uname) +endif + +TRUESYSTEM = $(shell uname) +MACHINE = $(shell uname -m) +DISTRIB = $(shell cat /etc/issue | cut -f 1 -d\ | head -1) + +CC = gcc +CXX = g++ +LD = g++ -m32 +AS = gcc -c -m32 +AR = ar rcs + +ifeq ($(SYSTEM),Darwin) + ARCH_FLAGS = -arch i386 + LIBS = -liconv + LD = g++ -arch i386 + STRIP = strip -x + ifeq ($(TRUESYSTEM),Linux) + CC = i686-apple-darwin9-gcc + CXX = i686-apple-darwin9-g++ + LD = i686-apple-darwin-g++ -arch i386 -mmacosx-version-min=10.5 + STRIP = i686-apple-darwin-strip -x + AS = i686-apple-darwin-as -arch i386 + endif +else + ARCH_FLAGS = -march=i686 -m32 + ASFLAGS = -march=i686 --32 + STRIP = strip --strip-unneeded +endif + +INCLUDES = -Iincludes + +CPPFLAGS_NO_ARCH += $(INCLUDES) -g -DSTDC_HEADERS -fexceptions -DWORDS_LITTLEENDIAN $(HAVES) +CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) + +LDFLAGS += $(ARCH_FLAGS) $(LIBS) + +vpath %.cc src:tests + +BALAU_SOURCES = \ +BString.cc \ +Local.cc \ +Main.cc \ +Printer.cc \ + +TEST_SOURCES = \ +test-String.cc \ + +LIB = libBalau.a + +WHOLE_SOURCES = $(BALAU_SOURCES) $(TEST_SOURCES) +TESTS = $(notdir $(basename $(TEST_SOURCES))) + +BALAU_OBJECTS = $(addsuffix .o, $(notdir $(basename $(BALAU_SOURCES)))) +ALL_OBJECTS = $(addsuffix .o, $(notdir $(basename $(WHOLE_SOURCES)))) +ALL_DEPS = $(addsuffix .dep, $(notdir $(basename $(WHOLE_SOURCES)))) + +all: dep lib + +tests: $(TESTS) + for t in $(TESTS) ; do ./$$t ; done + +lib: $(LIB) + +libBalau.a: $(BALAU_OBJECTS) + $(AR) libBalau.a $(BALAU_OBJECTS) + +test-String: test-String.o $(LIB) + $(LD) -o $@ $< ./$(LIB) + +dep: $(ALL_DEPS) + +%.dep : %.cc + $(CXX) $(CPPFLAGS_NO_ARCH) -M -MF $@ $< + +-include $(ALL_DEPS) + +clean: + rm -f $(ALL_OBJECTS) $(TESTS) $(LIB) $(ALL_DEPS) + +.PHONY: lib tests clean diff --git a/includes/BString.h b/includes/BString.h new file mode 100644 index 0000000..5356310 --- /dev/null +++ b/includes/BString.h @@ -0,0 +1,97 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Balau { + +class String : private std::string { + public: + String() : std::string() { } + String(const char * str) : std::string(str) { } + String(const char * str, size_t n) : std::string(str, n) { } + String(char c) { set("%c", c); } + String(int32_t i) { set("%i", i); } + String(uint32_t i) { set("%u", i); } + String(int64_t i) { set("%lli", i); } + String(uint64_t i) { set("%llu", i); } + String(double d) { set("%g", d); } + String(const String & s) : std::string(s) { } + String(const std::string & s) : std::string(s) { } + + void set(const char * fmt, va_list); + void set(const char * fmt, ...) { va_list ap; va_start(ap, fmt); set(fmt, ap); va_end(ap); } + void set(const String & fmt, ...) { va_list ap; va_start(ap, fmt); set(fmt.to_charp(), ap); va_end(ap); } + + int scanf(const char * fmt, va_list ap) const { return ::vsscanf(c_str(), fmt, ap); } + int scanf(const char * fmt, ...) const { va_list ap; va_start(ap, fmt); int r = scanf(fmt, ap); va_end(ap); return r; } + int scanf(const String & fmt, ...) const { va_list ap; va_start(ap, fmt); int r = scanf(fmt.to_charp(), ap); va_end(ap); return r; } + + const char * to_charp(size_t begin = 0) const { return c_str() + begin; } + String extract(size_t begin = 0, size_t size = static_cast(-1)) const { return substr(begin, size); } + char * strdup(size_t begin = 0, size_t size = static_cast(-1)) const { + if (begin == 0) + return ::strdup(to_charp()); + else + return ::strdup(extract(begin, size).to_charp()); + } + + int to_int(int base = 0) const { return strtol(to_charp(), NULL, base); } + double to_double() const { return strtod(to_charp(), NULL); } + + size_t strlen() const { return std::string::length(); } + ssize_t strchr(char c, size_t begin = 0) const { return find(c, begin); } + ssize_t strrchr(char c) const { return rfind(c); } + ssize_t strstr(const String & s, size_t begin = 0) const { return find(std::string(s), begin); } + ssize_t strstr(const char * s, size_t begin = 0) const { return find(std::string(s), begin); } + int strchrcnt(char) const; + + String ltrim() const { String c = *this; return c.do_ltrim(); } + String rtrim() const { String c = *this; return c.do_rtrim(); } + String trim() const { String c = *this; return c.do_trim(); } + String upper() const { String c = *this; return c.do_upper(); } + String lower() const { String c = *this; return c.do_lower(); } + String iconv(const String & from, const String & to) const { String c = *this; c.do_iconv(from.to_charp(), to.to_charp()); return c; } + String iconv(const char * from, const char * to) const { String c = *this; c.do_iconv(from, to); return c; } + + String & do_ltrim(); + String & do_rtrim(); + String & do_trim() { return do_ltrim().do_rtrim(); } + String & do_upper(); + String & do_lower(); + String & do_iconv(const String & from, const String & to) { return do_iconv(from.to_charp(), to.to_charp()); } + String & do_iconv(const char * from, const char * to); + + String & operator=(const String & v) { *((std::string *) this) = std::string::assign(v); return *this; } + String & operator=(const char * v) { *((std::string *) this) = std::string::assign(v); return *this; } + + String operator+(const String & v) const { String r = *this; r += v; return r; } + String operator+(const char * v) const { String r = *this; r += v; return r; } + String & operator+=(const String & v) { *this = append(v); return *this; } + String & operator+=(const char * v) { *this = append(v); return *this; } + + int compare(const String & v) const { return std::string::compare(v); } + int compare(const char * v) const { return std::string::compare(v); } + + bool operator==(const String & v) const { return compare(v) == 0; } + bool operator==(const char * v) const { return compare(v) == 0; } + bool operator!=(const String & v) const { return compare(v) != 0; } + bool operator!=(const char * v) const { return compare(v) != 0; } + bool operator<(const String & v) const { return compare(v) < 0; } + bool operator<(const char * v) const { return compare(v) < 0; } + bool operator<=(const String & v) const { return compare(v) <= 0; } + bool operator<=(const char * v) const { return compare(v) <= 0; } + bool operator>(const String & v) const { return compare(v) > 0; } + bool operator>(const char * v) const { return compare(v) > 0; } + bool operator>=(const String & v) const { return compare(v) >= 0; } + bool operator>=(const char * v) const { return compare(v) >= 0; } + + const char & operator[](size_t i) const { return at(i); } + char & operator[](size_t i) { return at(i); } +}; + +}; diff --git a/includes/Exceptions.h b/includes/Exceptions.h new file mode 100644 index 0000000..39f3239 --- /dev/null +++ b/includes/Exceptions.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace Balau { + +class GeneralException { + public: + GeneralException(const char * msg) : m_msg(::strdup(msg)) { } + GeneralException(const String & msg) : m_msg(msg.strdup()) { } + GeneralException(const GeneralException & e) : m_msg(strdup(e.m_msg)) { } + ~GeneralException() { if (m_msg) free(m_msg); } + const char * getMsg() const { return m_msg; } + + protected: + GeneralException() : m_msg(0) { } + void setMsg(char * msg) { if (m_msg) free(m_msg); m_msg = msg; } + private: + char * m_msg; +}; + +static inline void AssertHelper(const String & msg) throw(GeneralException) { throw GeneralException(msg); } + +}; + +#define Assert(c) if (!(c)) { \ + Balau::String msg; \ + msg.set("Assertion " #c " failed at %s:%i", __FILE__, __LINE__); \ + Balau::AssertHelper(msg); \ +} diff --git a/includes/Local.h b/includes/Local.h new file mode 100644 index 0000000..f3b7250 --- /dev/null +++ b/includes/Local.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace Balau { + +class TLSManager { + public: + virtual void * getTLS(); + virtual void * setTLS(void * val); +}; + +extern TLSManager * tlsManager; + +class Local : public AtStart { + public: + static int getSize() { return s_size; } + protected: + Local() : AtStart(0) { } + void * getGlobal() { return m_globals[m_idx]; } + void * getLocal() { return reinterpret_cast(getTLS())[m_idx]; } + void * get() { if (getTLS()) { void * l = getLocal(); return l ? l : getGlobal(); } else return getGlobal(); } + void setGlobal(void * obj) { m_globals[m_idx] = obj; } + void setLocal(void * obj) { void * r = getTLS(); reinterpret_cast(r)[m_idx] = obj; } + void set(void * obj) { void * r = getTLS(); if (r) setGlobal(obj); else setLocal(obj); } + int getIndex() { return m_idx; } + private: + static void * create() { void * r = malloc(s_size * sizeof(void *)); setTLS(r); return r; } + static void * getTLS() { return tlsManager->getTLS(); } + static void * setTLS(void * val) { return tlsManager->setTLS(val); } + virtual void doStart(); + int m_idx; + static int s_size; + static void ** m_globals; +}; + +}; diff --git a/includes/Main.h b/includes/Main.h new file mode 100644 index 0000000..eee7ff7 --- /dev/null +++ b/includes/Main.h @@ -0,0 +1,118 @@ +#pragma once + +#include + +namespace Balau { + +class AtStart { + protected: + AtStart(int priority = 0); + virtual void doStart() = 0; + private: + const int m_priority; + AtStart * m_next; + static AtStart * s_head; + friend class Main; +}; + +class AtExit { + protected: + AtExit(int priority = 0); + virtual void doExit() = 0; + private: + const int m_priority; + AtExit * m_next; + static AtExit * s_head; + friend class Main; +}; + +class Exit : public GeneralException { + public: + Exit(int code = -1) : GeneralException(), m_code(code) { String s; s.set("Application exitting with code = %i", code); setMsg(s.strdup()); } + int getCode() { return m_code; } + private: + int m_code; +}; + +}; + +#include + +namespace Balau { + +class Main { + public: + enum Status { + UNKNOWN = 0, + STARTING, + RUNNING, + STOPPING, + STOPPED, + }; + Main() : m_status(UNKNOWN) { application = this; } + virtual int startup() throw (GeneralException) = 0; + static Status status() { return application->m_status; } + int bootstrap(int _argc, char ** _argv) { + int r; + m_status = STARTING; + + argc = _argc; + argv = _argv; + enve = NULL; + + for (AtStart * ptr = AtStart::s_head; ptr; ptr = ptr->m_next) + ptr->doStart(); + + try { + m_status = RUNNING; + r = startup(); + m_status = STOPPING; + } + catch (Exit e) { + m_status = STOPPING; + r = e.getCode(); + } + catch (GeneralException e) { + m_status = STOPPING; + Printer::log(M_ERROR | M_ALERT, "The application caused an exception: %s", e.getMsg()); + r = -1; + } + catch (...) { + m_status = STOPPING; + Printer::log(M_ERROR | M_ALERT, "The application caused an unknown exception"); + r = -1; + } + m_status = STOPPING; + + for (AtExit * ptr = AtExit::s_head; ptr; ptr = ptr->m_next) + ptr->doExit(); + + m_status = STOPPED; + return r; + } + protected: + int argc; + char ** argv; + char ** enve; + private: + Status m_status; + static Main * application; +}; + +#define BALAU_STARTUP \ +\ +class Application : public Balau::Main { \ + public: \ + virtual int startup() throw (Balau::GeneralException); \ +}; \ +\ +static Application application; \ +\ +extern "C" { \ + int main(int argc, char ** argv) { \ + setlocale(LC_ALL, ""); \ + return application.bootstrap(argc, argv); \ + } \ +} + +}; diff --git a/includes/Printer.h b/includes/Printer.h new file mode 100644 index 0000000..b55df22 --- /dev/null +++ b/includes/Printer.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +namespace Balau { + +enum { + M_DEBUG = 1, + M_INFO = 2, + M_STATUS = 4, + M_WARNING = 8, + M_ERROR = 16, + M_ALERT = 32, + + M_ALL = M_DEBUG | M_INFO | M_STATUS | M_WARNING | M_ERROR | M_ALERT, + M_MAX = M_ALERT, +}; + +class Printer { + protected: + virtual void _print(const char * fmt, va_list ap); + + private: + void _log(uint32_t level, const char * fmt, va_list ap); + static Printer * getPrinter(); + + public: + Printer(); + + void setLocal(); + + static void log(uint32_t level, const String & fmt, ...) { va_list ap; va_start(ap, fmt); log(level, fmt.to_charp(), ap); va_end(ap); } + static void log(uint32_t level, const char * fmt, ...) { va_list ap; va_start(ap, fmt); log(level, fmt, ap); va_end(ap); } + static void log(uint32_t level, const char * fmt, va_list ap) { getPrinter()->_log(level, fmt, ap); } + static void print(const String & fmt, ...) { va_list ap; va_start(ap, fmt); print(fmt.to_charp(), ap); va_end(ap); } + static void print(const char * fmt, ...) { va_list ap; va_start(ap, fmt); print(fmt, ap); va_end(ap); } + static void print(const char * fmt, va_list ap) { getPrinter()->_print(fmt, ap); } + + void enable(uint32_t levels = M_ALL) { m_verbosity |= levels; } + void disable(uint32_t levels = M_ALL) { m_verbosity &= ~levels; } + + uint32_t m_verbosity; +}; + +}; diff --git a/src/BString.cc b/src/BString.cc new file mode 100644 index 0000000..61abb8c --- /dev/null +++ b/src/BString.cc @@ -0,0 +1,108 @@ +#include +#include + +#include "BString.h" + +void Balau::String::set(const char * fmt, va_list ap) { + char * t; + unsigned int l; +#ifdef _WIN32 + // Microsoft is stupid. + char tt[65536]; + l = _vsnprintf(tt, sizeof(tt) - 1, fmt, ap); + tt[65535] = 0; + t = ::strdup(tt); +#else + l = vasprintf(&t, fmt, ap); +#endif + assign(t, l); + free(t); +} + +int Balau::String::strchrcnt(char c) const { + unsigned int l = length(); + int r = 0; + const char * buffer = data(); + + for (unsigned int i = 0; i < l; i++) + if (buffer[i] == c) + r++; + + return r; +} + +Balau::String & Balau::String::do_ltrim() { + unsigned int l = length(), s = 0; + const char * buffer = data(); + + for (unsigned int i = 0; i < l; i++) + if (isspace(buffer[i])) + s++; + else + break; + + erase(0, s); + + return *this; +} + +Balau::String & Balau::String::do_rtrim() { + unsigned int l = length(), p = l; + const char * buffer = data(); + + for (unsigned int i = l - 1; i >= 0; i--) + if (isspace(buffer[i])) + p--; + else + break; + + erase(p); + + return *this; +} + +Balau::String & Balau::String::do_upper() { + unsigned int l = length(); + + for (unsigned int i = 0; i < l; i++) + (*this)[i] = toupper((*this)[i]); + + return *this; +} + +Balau::String & Balau::String::do_lower() { + unsigned int l = length(); + + for (unsigned int i = 0; i < l; i++) + (*this)[i] = tolower((*this)[i]); + + return *this; +} + +Balau::String & Balau::String::do_iconv(const char * from, const char * _to) { + iconv_t cd; + const String to = String(_to) + "//TRANSLIT"; + + const char * inbuf; + char * outbuf, * t; + size_t inleft, outleft; + + if ((cd = iconv_open(to.c_str(), from)) == (iconv_t) (-1)) + return *this; + + inleft = length(); + outleft = inleft * 8; + inbuf = c_str(); + t = outbuf = (char *) malloc(outleft + 1); + memset(t, 0, outleft + 1); +#ifdef HAVE_PROPER_ICONV + ::iconv(cd, &inbuf, &inleft, &outbuf, &outleft); +#else + ::iconv(cd, const_cast(&inbuf), &inleft, &outbuf, &outleft); +#endif + + assign(t, outbuf - t); + free(t); + + return *this; +} diff --git a/src/Local.cc b/src/Local.cc new file mode 100644 index 0000000..1262179 --- /dev/null +++ b/src/Local.cc @@ -0,0 +1,27 @@ +#include "Local.h" +#include "Main.h" + +static void * dummyTLS = NULL; + +void * Balau::TLSManager::getTLS() { + return dummyTLS; +} + +void * Balau::TLSManager::setTLS(void * val) { + void * r = dummyTLS; + dummyTLS = val; + return r; +} + +static Balau::TLSManager dummyTLSManager; +Balau::TLSManager * Balau::tlsManager = &dummyTLSManager; + +int Balau::Local::s_size = 0; +void ** Balau::Local::m_globals = 0; + +void Balau::Local::doStart() { + Assert(Main::status() == Main::STARTING); + m_idx = s_size++; + m_globals = reinterpret_cast(realloc(m_globals, s_size * sizeof(void *))); + m_globals[m_idx] = 0; +} diff --git a/src/Main.cc b/src/Main.cc new file mode 100644 index 0000000..04d867f --- /dev/null +++ b/src/Main.cc @@ -0,0 +1,34 @@ +#include "Main.h" + +Balau::AtStart * Balau::AtStart::s_head = 0; +Balau::AtExit * Balau::AtExit::s_head = 0; + +Balau::AtStart::AtStart(int priority) : m_priority(priority) { + if (priority < 0) + return; + + AtStart ** ptr = &s_head; + + m_next = 0; + + for (ptr = &s_head; *ptr && (priority > (*ptr)->m_priority); ptr = &((*ptr)->m_next)); + + m_next = *ptr; + *ptr = this; +} + +Balau::AtExit::AtExit(int priority) : m_priority(priority) { + if (priority < 0) + return; + + AtExit ** ptr = &s_head; + + m_next = 0; + + for (ptr = &s_head; *ptr && (priority > (*ptr)->m_priority); ptr = &((*ptr)->m_next)); + + m_next = *ptr; + *ptr = this; +} + +Balau::Main * Balau::Main::application = NULL; diff --git a/src/Printer.cc b/src/Printer.cc new file mode 100644 index 0000000..fda9952 --- /dev/null +++ b/src/Printer.cc @@ -0,0 +1,60 @@ +#include "Printer.h" +#include "Main.h" +#include "Local.h" + +class PrinterLocal : public Balau::Local { + public: + PrinterLocal() { } + Balau::Printer * getGlobal() { return reinterpret_cast(Local::getGlobal()); } + Balau::Printer * get() { return reinterpret_cast(Local::get()); } + void setGlobal(Balau::Printer * printer) { Local::setGlobal(printer); } + void set(Balau::Printer * printer) { Local::set(printer); } +} printerLocal; + +static const char * prefixes[] = { + "(DD) ", + "(II) ", + "(--) ", + "(WW) ", + "(EE) ", + "(AA) ", +}; + +Balau::Printer::Printer() : m_verbosity(M_STATUS | M_WARNING | M_ERROR) { + if (!printerLocal.getGlobal()) + printerLocal.setGlobal(this); +} + +Balau::Printer * Balau::Printer::getPrinter() { return printerLocal.get(); } + +void Balau::Printer::_log(uint32_t level, const char * fmt, va_list ap) { + if (!(level & m_verbosity)) + return; + + int l, i; + + for (l = M_MAX, i = (sizeof(prefixes) / sizeof(*prefixes)) - 1; l; l >>= 1, i--) + if (l & level) + break; + + print(prefixes[i]); + print(fmt, ap); + print("\n"); +} + +void Balau::Printer::_print(const char * fmt, va_list ap) { + vfprintf(stderr, fmt, ap); +} + +class DefaultPrinter : public Balau::AtStart { + public: + DefaultPrinter() : AtStart(10) { } + protected: + virtual void doStart(); +}; + +static DefaultPrinter defaultPrinter; + +void DefaultPrinter::doStart() { + new Balau::Printer(); +} diff --git a/tests/test-String.cc b/tests/test-String.cc new file mode 100644 index 0000000..36c87e4 --- /dev/null +++ b/tests/test-String.cc @@ -0,0 +1,50 @@ +#include +#include + +BALAU_STARTUP; + +using namespace Balau; + +int Application::startup() throw (Balau::GeneralException) { + Printer::log(M_STATUS, "Test::String running."); + + String x = "foobar"; + Assert(x == "foobar"); + Assert(x != "barfoo"); + + String y = "xyz"; + + x = "abcdef"; Assert(x < y); Assert(x + y == "abcdefxyz"); + x.set("x:%i", 42); Assert(x == "x:42"); + + x = "foobar"; Assert(x == "foobar"); + + y = x.extract(3); Assert(y == "bar"); + y = x.extract(1, 3); Assert(y == "oob"); + + y = " foo bar "; + x = y; x.do_ltrim(); Assert(x == "foo bar "); + x = y; x.do_rtrim(); Assert(x == " foo bar"); + x = y; x.do_trim(); Assert(x == "foo bar"); + + x = "42"; Assert(x.to_int() == 42); + x = "0x42"; Assert(x.to_int() == 0x42); + x = "42"; Assert(x.to_int(16) == 0x42); + x = "4.2"; Assert(x.to_double() == 4.2); + + x = "foobar"; + Assert(x[0] == 'f'); + Assert(x[5] == 'r'); + Assert(x.strlen() == 6); + Assert(x.strchr('o') == 1); + Assert(x.strrchr('o') == 2); + Assert(x.strchrcnt('o') == 2); + Assert(x.strstr("bar") == 3); + + x = "\xc3\xa9"; + y = x.iconv("UTF-8", "Latin1"); + Assert(((unsigned char) y[0]) == 0xe9); + + Printer::log(M_STATUS, "Test::String passed."); + return 0; +} -- cgit v1.2.3