diff options
Diffstat (limited to 'generic')
-rw-r--r-- | generic/Buffer.cpp | 106 | ||||
-rw-r--r-- | generic/Exceptions.cpp | 152 | ||||
-rw-r--r-- | generic/Handle.cpp | 269 | ||||
-rw-r--r-- | generic/Image.cpp | 86 | ||||
-rw-r--r-- | generic/Input.cpp | 70 | ||||
-rw-r--r-- | generic/Output.cpp | 68 | ||||
-rw-r--r-- | generic/String.cpp | 358 |
7 files changed, 1109 insertions, 0 deletions
diff --git a/generic/Buffer.cpp b/generic/Buffer.cpp new file mode 100644 index 0000000..edd70bc --- /dev/null +++ b/generic/Buffer.cpp @@ -0,0 +1,106 @@ +#include <string.h> +#include "Buffer.h" +#include "General.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define _(x) x +#endif + +Buffer::Buffer() : Handle(-1), buffer(0), zero(0), realsiz(0), bufsiz(0), ptr(0) { } + +Buffer::~Buffer() { + free(buffer); +} + +Buffer::Buffer(const Buffer & b) : Handle(-1), buffer(0), zero(b.zero), realsiz(b.realsiz), bufsiz(b.bufsiz), ptr(b.ptr) { + buffer = (char *) malloc(bufsiz); + memcpy(buffer, b.buffer, bufsiz); +} + +ssize_t Buffer::write(const void *buf, size_t count) throw (GeneralException) { + if (!count) { + return 0; + } + if (count + realsiz > bufsiz) { + int numblocks = (count + realsiz) / realloc_threshold; + int remains = (count + realsiz) % realloc_threshold; + buffer = (char *) realloc(buffer, bufsiz = ((numblocks + (remains ? 1 : 0)) * realloc_threshold)); + } + memcpy(buffer + realsiz, buf, count); + realsiz += count; + + return count; +} + +ssize_t Buffer::read(void *buf, size_t count) throw (GeneralException) { + count = MIN(count, realsiz - ptr); + + if (!count) { + return 0; + } + + memcpy(buf, buffer + ptr, count); + ptr += count; + + if (ptr >= realloc_threshold) { + int numblocks = (bufsiz / realloc_threshold) - (ptr / realloc_threshold); + memmove(buffer, buffer + (bufsiz - numblocks * realloc_threshold), numblocks * realloc_threshold); + ptr -= (bufsiz - numblocks * realloc_threshold); + realsiz -= (bufsiz - numblocks * realloc_threshold); + buffer = (char *) realloc(buffer, bufsiz = (numblocks * realloc_threshold)); + } + + return count; +} + +bool Buffer::CanRead() { + return true; +} + +bool Buffer::CanWrite() { + return true; +} + +String Buffer::GetName() { + return "Buffer"; +} + +Buffer Buffer::operator=(const Buffer & b) { + if (b.buffer != buffer) { + free(buffer); + realsiz = b.realsiz; + ptr = b.ptr; + if ((bufsiz = b.bufsiz)) { + buffer = (char *) malloc(bufsiz); + memcpy(buffer, b.buffer, realsiz); + } else { + buffer = 0; + } + } + return *this; +} + +bool Buffer::CanWatch() { + return false; +} + +ssize_t Buffer::GetSize() { + return realsiz; +} + +char Buffer::operator[](size_t p) const { + if (p >= realsiz) { + return 0; + } else { + return buffer[ptr + p]; + } +} + +char & Buffer::operator[](size_t p) { + if (p >= realsiz) { + return zero; + } else { + return buffer[ptr + p]; + } +} diff --git a/generic/Exceptions.cpp b/generic/Exceptions.cpp new file mode 100644 index 0000000..b541235 --- /dev/null +++ b/generic/Exceptions.cpp @@ -0,0 +1,152 @@ +#include <malloc.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stddef.h> +#include "String.h" +#include "Exceptions.h" +#include "General.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define _(x) x +#endif + +char GeneralException::t[BUFSIZ]; + +GeneralException::GeneralException(String emsg) : msg(emsg.strdup()) { +#ifdef DEBUG + cerr << _("Generating a General Exception error: '") << msg << "'.\n"; +#endif +} +GeneralException::GeneralException() : msg(0) { +#ifdef DEBUG + cerr << _("Generating a General Exception error: '") << msg << "'.\n"; +#endif +} +GeneralException::GeneralException(const GeneralException & e) : msg(strdup(e.msg)) { +#ifdef DEBUG + cerr << _("Generating a General Exception error: '") << msg << "'.\n"; +#endif +} + +GeneralException::~GeneralException() { + free(msg); +} + +TaskNotFound::TaskNotFound() : GeneralException("Task not found") { } + +char * GeneralException::GetMsg() { + return msg; +} + +MemoryException::MemoryException(ssize_t s) { + sprintf(t, _("Failed allocating %u bytes."), s); + msg = strdup(t); +} + +IOException::IOException(String fn, op_t op, ssize_t s) { + sprintf(t, _("An error has occured while %s %u bytes on %s: %s"), op == IO_WRITE ? _("writing") : _("reading"), + s, fn.to_charp(), strerror(errno)); + msg = strdup(t); +} + +IOGeneral::IOGeneral(String fn) : GeneralException(fn) { } + +IOGeneral::IOGeneral() { } + +IOAgain::IOAgain() : IOGeneral(_("No more bytes for reading or writing.")) { +#ifdef DEBUG + cerr << "Generating an IOAgain exception: '" << GetMsg() << "'.\n"; +#endif +} + +TaskSwitch::TaskSwitch() : GeneralException(_("Switching task in a non-tasked environnement")) { +#ifdef DEBUG + cerr << "Generating a TaskSwitch exception: '" << GetMsg() << "'.\n"; +#endif +} + +char * xstrdup(const char * s) { + char * r; + + r = (char *) xmalloc(strlen(s) + 1); + strcpy(r, s); + return r; +} + +void * xmalloc(size_t s) throw (GeneralException) { + char * r; + + if (!s) { + return 0; + } + + if (!(r = (char *) ::malloc(s + sizeof(size_t)))) { + throw MemoryException(s + sizeof(size_t)); + } + + memset(r, 0, s + sizeof(size_t)); + + *((size_t *)r) = s; + + return (void *)(r + sizeof(size_t)); +} + +void * xrealloc(void * ptr, size_t s) { + char * r; + size_t os; + + if (!ptr) { + return xmalloc(s); + } + + os = *(((size_t *) ptr) - 1); + + r = (char *) xmalloc(s); + + if (s) { + memcpy(r, ptr, MIN(s, os)); + } + + xfree(ptr); + return r; +} + +#ifdef OVER_FREE +#undef free +#endif + +void xfree(void *& p) { + if (p) { + ::free(((char *)p) - sizeof(size_t)); + p = 0; + } +} + +void xfree(char *& p) { + if (p) { + ::free(p - sizeof(size_t)); + p = 0; + } +} + +int xpipe(int * p, int flag) throw (GeneralException) { + if (pipe(p)) { + throw GeneralException(String(_("Error creating pipe: ")) + strerror(errno)); + } + + return p[flag]; +} + +pid_t xfork() throw (GeneralException) { + pid_t p; + + p = fork(); + + if (p == -1) { + throw GeneralException(_("Was not able to fork().\n")); + } + + return p; +} diff --git a/generic/Handle.cpp b/generic/Handle.cpp new file mode 100644 index 0000000..8b7a278 --- /dev/null +++ b/generic/Handle.cpp @@ -0,0 +1,269 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include "Handle.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define _(x) x +#endif + +Handle::Handle(const Handle & nh) : h(nh.h >= 0 ? dup(nh.h) : nh.h), closed(nh.closed), nonblock(nh.closed), zfile(0), z(0) { +// cerr << "Duplication of handle " << nh.h << " to " << h << endl; + if ((h >= 0) && (nh.z)) { + SetZ(nh.z); + } +} + +Handle::~Handle() { +// cerr << "Destroying handle " << h << endl; + close(); +} + +Handle::Handle(int nh) : h(nh), closed(false), nonblock(false), zfile(0), z(0) { +// cerr << "Initialising handle " << h << endl; +} + +int Handle::GetHandle() { + return h; +} + +ssize_t Handle::write(const void *buf, size_t count) throw (GeneralException) { + ssize_t r, tr = 0; + bool done, full = false; + + do { + done = true; + errno = 0; + if ((r = uwrite(buf, count)) < 0) { + if ((!errno) || (errno == EAGAIN) || (errno == EINTR)) { + // Avant de déclarer une erreur, on vérifie si ce n'est pas un + // problème lié au fait qu'il n'y a plus de place libre. Cela peut + // arriver si l'on agit sur un pipe ou un handle. Nous + // attendons encore une fois avant de déclarer l'erreur, + // grace au drapeau full. + if (full) { + throw IOException(GetName(), IO_WRITE, count); + } else { + done = false; + full = true; + if (nonblock) { +// cerr << "write: throwing IOAgain for handle " << GetName() << endl; + throw IOAgain(); + } else { + sleep(1); + } + } + } else { + throw IOException(GetName(), IO_WRITE, count); + } + } else if (((size_t) r) != count) { + if (nonblock) { + return r; + } + full = done = false; + ((char *)buf) += r; + tr += r; + } + } while (!done); + + return r + tr; +} + +ssize_t Handle::read(void *buf, size_t count) throw (GeneralException) { + ssize_t r; + + errno = 0; + while ((r = uread(buf, count)) < 0) { + if ((!errno) || (errno == EAGAIN) || (errno == EINTR)) { + // Avant de déclarer une erreur, on vérifie si ce n'est pas un + // problème lié au fait qu'il n'y a plus d'octets. + if (nonblock) { +// cerr << "read: throwing IOAgain for handle " << GetName() << endl; + throw IOAgain(); + } + } else { + throw IOException(GetName(), IO_READ, count); + } + } + + if (!r) { + close(); + } + + return r; +} + +bool Handle::IsClosed(void) { + return closed; +} + +bool Handle::IsNonBlock(void) { + return nonblock; +} + +void Handle::SetNonBlock(void) { + if ((h >= 0) || !nonblock) { + fcntl(h, F_SETFL, O_NONBLOCK); + } + nonblock = true; +} + +Handle & operator<<(Handle & h, const String & s) { + const char * p; + + p = s.to_charp(); + h.write(p, strlen(p)); + + return h; +} + +Handle & operator>>(Handle & h, String & s) { + char t[BUFSIZ]; + int i = 0, r; + + while ((r = h.read(&(t[i]), 1)) && (i != (BUFSIZ - 1))) { + // Il y a souvent des \r\n dans les sockets par exemple, + // ou bien en lisant des fichiers au format MS-DOS. On + // ignore le \r pour ne garder que le \n, standard sous Unix. + if (t[i] == '\r') { + continue; + } + if (t[i] == '\n') { + break; + } else { + i++; + } + } + + t[i] = '\0'; + s = t; + return h; +} + +void Handle::close() throw (GeneralException) { + if (IsClosed()) { + return; + } + + if (h >= 0) { + if (z) { +// cerr << "Performing gzclose on handle " << h << endl; + int err = gzclose(zfile); +// cerr << "gzclose returned " << err << endl; + if (err) { + if (err == Z_ERRNO) { + throw GeneralException(String(_("Error during close: ")) + strerror(errno)); + } else { + throw GeneralException(_("Error in zlib during gzclose.")); + } + } + } else { + int err = ::close(h); + if (err) { + throw GeneralException(String(_("Error during close: ")) + strerror(errno)); + } + } + } + + h = -1; + + closed = 1; +} + +bool Handle::CanRead(void) { + return false; +} + +bool Handle::CanWrite(void) { + return false; +} + +String Handle::GetName(void) { + return _("Bare Handle - should not happend"); +} + +ssize_t Handle::GetSize(void) { + return -1; +} + +time_t Handle::GetModif(void) { + return -1; +} + +bool Handle::CanWatch(void) { + return true; +} + +void Handle::Dup(const Handle & H) { + close(); + if (H.h >= 0) { + h = dup(H.h); + } +} + +void Handle::SetZ(int az) throw (GeneralException) { + if (z) { + throw GeneralException(_("Can't SetZ a Handle twice.")); + } + if (h < 0) { + throw GeneralException(_("Can't SetZ a virtual Handle.")); + } + if (az) { + char format[4]; + int index = 0; + if (CanRead()) { + format[index++] = 'r'; + } + if (CanWrite()) { + format[index++] = 'w'; + } + format[index++] = (char) (az + '0'); + format[index] = 0; +// cerr << "Performing gzdopen on handle " << h << " with mode \"" << format << "\"\n"; + if (!(zfile = gzdopen(h, format))) { + throw GeneralException(_("Was not able to gzdopen.")); + } + z = az; + } +} + +ssize_t Handle::uwrite(const void * buf, size_t count) throw (GeneralException) { + if (z) { +// cerr << "Performing gzwrite of " << count << " byte for handle " << h << endl; + int err = gzwrite(zfile, buf, count); +// cerr << "gzwrite returned " << err << endl; + if (err == 0) { + const char * m = gzerror(zfile, &err); + if (err == Z_ERRNO) { + return -1; + } else { + throw GeneralException(String(_("Error in zlib during gzwrite: ")) + m); + } + } + return err; + } else { + return ::write(h, buf, count); + } +} + +ssize_t Handle::uread(void * buf, size_t count) { + if (z) { +// cerr << "Performing gzread of " << count << " byte for handle " << h << endl; + int err = gzread(zfile, buf, count); +// cerr << "gzwrite returned " << err << endl; + if (err == -1) { + gzerror(zfile, &err); + if (err == Z_ERRNO) { + return -1; + } else { + return 0; + } + } + return err; + } else { + return ::read(h, buf, count); + } +} diff --git a/generic/Image.cpp b/generic/Image.cpp new file mode 100644 index 0000000..1270a6a --- /dev/null +++ b/generic/Image.cpp @@ -0,0 +1,86 @@ +#include "Image.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define _(x) x +#endif + +Image::Image(unsigned int ax, unsigned int ay) : x(ax), y(ay), img((Color *) malloc(x * y * sizeof(Color))) { + Fill(); +} + +Image::~Image() { + free((void *)img); +} + +bool Image::CanWrite() { + return false; +} + +String Image::GetName() { + return String(_("Image ")) + x + "x" + y; +} + +void Image::Fill(Color c) { + for (unsigned int i = 0; i < x * y; i++) { + img[i] = c; + } +} + +Color Image::GetPixel(unsigned int px, unsigned int py) { + if ((px >= x) || (py >= y)) { + return Color(0, 0, 0, 0); + } + + return img[x * py + px]; +} + +void Image::SetPixel(unsigned int px, unsigned int py, Color c) { + if ((px >= x) || (py >= y)) { + return; + } + + img[x * py + px] = c; +} + +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN 0 +#endif + +bool Image::Prepare(unsigned int f) { + if (GetSize()) return false; + + switch (f) { + case FORMAT_TGA_BASIC: + TGAHeader Header; + TGAFooter Footer; + + Header.IDLength = 0; + Header.ColorMapType = 0; + Header.ImageType = 2; + Header.CM_FirstEntry = 0; + Header.CM_Length = 0; + Header.CM_EntrySize = 0; + Header.IS_XOrigin = 0; + Header.IS_YOrigin = 0; + Header.IS_Width = WORDS_BIGENDIAN ? ((x & 0xff) << 8) | ((x & 0xff00) >> 8) : x; + Header.IS_Height = WORDS_BIGENDIAN ? ((y & 0xff) << 8) | ((y & 0xff00) >> 8) : y; + Header.IS_Depth = 32; + Header.IS_Descriptor = 0x20; + + Footer.ExtOffset = 0; + Footer.DevOffset = 0; + strcpy(Footer.Sig, "TRUEVISION-XFILE."); + + write(&Header, sizeof(Header)); + write(img, x * y * sizeof(Color)); + write(&Footer, sizeof(Footer)); + + return true; + + break; + default: + return false; + } +} + diff --git a/generic/Input.cpp b/generic/Input.cpp new file mode 100644 index 0000000..7106c8d --- /dev/null +++ b/generic/Input.cpp @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "Input.h" +#include "Exceptions.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define _(x) x +#endif + +Input::Input(String no) throw (GeneralException) : + Handle(no.strlen() ? open(no.to_charp(), O_RDONLY) : dup(0)), + n(no) { + if (GetHandle() < 0) { + throw IOGeneral(String(_("Error opening file ")) + no + _(" for reading: ") + strerror(errno)); + } + + size = lseek(GetHandle(), 0, SEEK_END); + lseek(GetHandle(), 0, SEEK_SET); + + struct stat s; + + fstat(GetHandle(), &s); + + date_modif = s.st_mtime; +} + +Input::Input(const Input & i) : Handle(i), n(i.n), size(i.size), date_modif(i.date_modif) { +} + +bool Input::CanWrite() { + return 0; +} + +bool Input::CanRead() { + return 1; +} + +String Input::GetName() { + return n; +} + +ssize_t Input::GetSize() { + return size; +} + +time_t Input::GetModif() { + return date_modif; +} + +Stdin_t::Stdin_t() : Handle(dup(0)) { } + +bool Stdin_t::CanWrite() { + return 0; +} + +bool Stdin_t::CanRead() { + return 1; +} + +String Stdin_t::GetName() { + return "Stdin"; +} + +Stdin_t Stdin; diff --git a/generic/Output.cpp b/generic/Output.cpp new file mode 100644 index 0000000..dbc1892 --- /dev/null +++ b/generic/Output.cpp @@ -0,0 +1,68 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "Output.h" +#include "Exceptions.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define _(x) x +#endif + +Output::Output(String no, int trunc) throw (GeneralException) : + Handle(no.strlen() ? open(no.to_charp(), O_WRONLY | O_CREAT | (trunc ? O_TRUNC : O_APPEND), 00666) : dup(1)), + n(no) { + if (GetHandle() < 0) { + throw IOGeneral(String(_("Error opening file ")) + no + _(" for writing: ") + strerror(errno)); + } +} + +Output::Output(const Output & o) : Handle(o), n(o.n) { +} + +bool Output::CanWrite() { + return 1; +} + +bool Output::CanRead() { + return 0; +} + +String Output::GetName() { + return n; +} + +Stdout_t::Stdout_t() : Handle(dup(1)) {} + +bool Stdout_t::CanWrite() { + return 1; +} + +bool Stdout_t::CanRead() { + return 0; +} + +String Stdout_t::GetName() { + return "Stdout"; +} + +Stderr_t::Stderr_t() : Handle(dup(2)) {} + +bool Stderr_t::CanWrite() { + return 1; +} + +bool Stderr_t::CanRead() { + return 0; +} + +String Stderr_t::GetName() { + return "Stderr"; +} + +Stdout_t Stdout; +Stderr_t Stderr; diff --git a/generic/String.cpp b/generic/String.cpp new file mode 100644 index 0000000..d6a1e01 --- /dev/null +++ b/generic/String.cpp @@ -0,0 +1,358 @@ +#include <iostream.h> +#include <string.h> +#include <stdarg.h> +#include "String.h" +#include "Exceptions.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define _(x) x +#endif + +extern "C" { + double dateCalc(char *, char *); + int isDateArgument(char *); +} + +char String::t[BUFSIZ + 1]; + +String::String(const String & s) : str(Base::strdup(s.str)), siz(s.siz) { } + +String::String(char c) : siz(1) { + char * t = (char *) malloc(2); + + sprintf(t, "%c", c); + str = t; +} + +String::String(const char * s) : str(s ? Base::strdup(s) : Base::strdup("")) { + siz = ::strlen(str); +} + +String::String(int hs, const char * s) : str(s ? Base::strdup(s) : Base::strdup("")), siz(hs) { } + +String::String(int i) { + char t[20]; + + sprintf(t, "%i", i); + str = Base::strdup(t); + siz = ::strlen(str); +} + +String::String(unsigned int i) { + char t[20]; + + sprintf(t, "%u", i); + str = Base::strdup(t); + siz = ::strlen(str); +} + +#ifdef USE_LONGLONG +String::String(long long l) { + char t[40]; + + sprintf(t, "%lld", l); + str = Base::strdup(t); + siz = ::strlen(str); +} + +String::String(unsigned long long l) { + char t[40]; + + sprintf(t, "%llu", l); + str = Base::strdup(t); + siz = ::strlen(str); +} +#endif + +String::String(double d) { + char t[30]; + + sprintf(t, "%g", d); + str = Base::strdup(t); + siz = ::strlen(str); +} + +String::~String() { + free(str); +} + +const char * String::set(const char * s, ...) { + va_list ap; + +/* This causes a warning: cannot pass objects of type `const String' through `...' + but it is not really a problem. */ + va_start(ap, s); + vsnprintf(t, BUFSIZ, s, ap); + free(str); + str = Base::strdup(t); + va_end(ap); + siz = ::strlen(str); + return t; +} + +const char * String::set(const String & s, ...) { + va_list ap; + + va_start(ap, s); + vsnprintf(t, BUFSIZ, s.str, ap); + free(str); + str = Base::strdup(t); + va_end(ap); + siz = ::strlen(str); + return t; +} + +const char * String::to_charp(size_t from, ssize_t to) const { + if (to < 0) { + strncpy(t, &(str[from]), BUFSIZ); + } else { + if (((size_t) to) >= siz) { + to = siz - 1; + } + + if ((((size_t) to) - from) > BUFSIZ) { + from -= (to - from) - BUFSIZ; + } + + if (((size_t) to) >= from) { + size_t i; + for (i = 0; i <= ((size_t) to) - from; i++) { + t[i] = str[i + from]; + } + t[i] = '\0'; + } else { + t[0] = '\0'; + } + } + return t; +} + +String String::extract(size_t from, ssize_t to) const { + return String(to_charp(from, to)); +} + +char * String::strdup(size_t from, ssize_t to) const { + return Base::strdup(to_charp(from, to)); +} + +int String::to_int(void) const { + int r; + + sscanf(str, "%i", &r); + return r; +} + +double String::to_double(void) const { + double r; + + sscanf(str, "%lf", &r); + return r; +} + +String & String::operator=(const String & s) { + if (str != s.str) { + // On évite l'autodestruction... + free(str); + str = s.strdup(); + siz = s.siz; + } + return *this; +} + +String String::operator+(const String & s) const { + char * t = (char *) malloc(s.siz + siz + 1), * u; + String o; + + strcpy((u = t), str); + u += siz; + strcpy(u, s.str); + o = String(siz + s.siz, t); + free(t); + return o; +} + +String & String::operator+=(const String & s) { + char * t = (char *) malloc(s.siz + siz + 1), * u; + + strcpy((u = t), str); + u += siz; + strcat(u, s.str); + free(str); + str = t; + siz += s.siz; + return (*this); +} + +ostream & operator<<(ostream & os, const String & s) { + return (os << s.to_charp()); +} + +istream & operator>>(istream & is, String & s) { + char c = 0; + + s.set(""); + + while (!is.eof()) { + c = is.get(); + if (c == '\n') return is; + if (c == '\r') continue; + s += c; + } + + return is; +} + +bool String::operator!=(const String & s) const { + return (strcmp(str, s.str) != 0); +} + +bool String::operator==(const String & s) const { + return (strcmp(str, s.str) == 0); +} + +bool String::operator<=(const String & s) const { + return (strcmp(str, s.str) <= 0); +} + +bool String::operator>=(const String & s) const { + return (strcmp(str, s.str) >= 0); +} + +bool String::operator<(const String & s) const { + return (strcmp(str, s.str) < 0); +} + +bool String::operator>(const String & s) const { + return (strcmp(str, s.str) > 0); +} + +size_t String::strlen() const { + return (siz); +} + +char String::operator[](size_t i) const { + if (i >= siz) { + return 0; + } else { + return str[i]; + } +} + +ssize_t String::strchr(char c, size_t from) const { + for (size_t i = from; i < siz; i++) { + if (str[i] == c) return i; + } + + return -1; +} + +ssize_t String::strrchr(char c) const { + for (size_t i = siz - 1; i >= 0; i--) { + if (str[i] == c) return i; + } + + return -1; +} + +ssize_t String::strstr(const String & s) const { + char * p = ::strstr(str, s.str); + + if (p) { + return p - str; + } else { + return -1; + } +} + +int String::strchrcnt(char c) const { + size_t i, cnt = 0; + for (i = 0; i < siz; i++) { + if (str[i] == c) cnt++; + } + + return cnt; +} + +String String::to_sqldate(void) const { +/* DD/MM/YYYY ==> YYYYMMMDD */ + return (is_date() ? extract(6, 9) + extract(3, 4) + extract(0, 1) : ""); +} + +String String::to_sqltime(void) const { +/* h:m ==> h * 60 + m */ + int p = strchr(':'); + return (is_time() ? String(extract(0, p - 1).to_int() * 60 + extract(p + 1).to_int()) : ""); +} + +String String::from_sqldate(void) const { +/* YYYYMMDD ==> DD/MM/YYYY */ + return ((strlen() == 8) && is_number() ? extract(6, 7) + '/' + extract(4, 5) + '/' + extract(0, 3) : ""); +} + +String String::from_sqltime(void) const { +/* t ==> (t / 60):(t % 60) */ + int t = to_int(); + return (is_number() ? String((int) (t / 60)) + ':' + (t % 60) : ""); +} + +bool String::is_date(void) const { +/* 'DD/MM/YYYY' + 0123456789 */ + + if (strlen() != 10) return false; + if ((str[2] != '/') || (str[5] != '/') || + (!extract(0, 1).is_number()) || + (!extract(3, 4).is_number()) || + (!extract(6, 9).is_number())) { + return (isDateArgument(to_sqldate().str)); + } + + return true; +} + +double String::datedif(const String & s) const { + double r; + if (is_date() && s.is_date()) { + r = dateCalc(str, s.str); + return r < 0 ? -r : r; + } + + return -1; +} + +bool String::is_number(void) const { + for (size_t i = ((str[0] == '-') ? 1 : 0); i < siz; i++) { + if ((str[i] > '9') || (str[i] < '0')) return false; + } + return true; +} + +bool String::is_float(void) const { + bool seendot = false; + + for (size_t i = ((str[0] == '-') ? 1 : 0); i < siz; i++) { + if ((str[i] > '9') || (str[i] < '0')) { + if ((str[i] == '.') && !seendot) { + seendot = true; + } else { + return false; + } + } + } + + return true; +} + +bool String::is_time(void) const { + int p = strchr(':'); + + if (p == -1) return false; + + // On accepte les heures sous le format xxxxxx:yy pour pouvoir indiquer des durées. + + if ((!extract(0, p - 1).is_number()) || (!extract(p + 1).is_number())) + return false; + + return (extract(p + 1).to_int() < 60) ? true : false; +} |