summaryrefslogtreecommitdiff
path: root/generic
diff options
context:
space:
mode:
authorPixel <Pixel>2002-07-21 11:12:13 +0000
committerPixel <Pixel>2002-07-21 11:12:13 +0000
commit6528f07c516efe4d3b344f01740067878d5d9a43 (patch)
treef097e6797752dffe7b498a4f153e83bdeb59f024 /generic
parentb54786a5120b48bd98fc4b199176d45bda3c2d67 (diff)
Hello Baltisot
Diffstat (limited to 'generic')
-rw-r--r--generic/Buffer.cpp106
-rw-r--r--generic/Exceptions.cpp152
-rw-r--r--generic/Handle.cpp269
-rw-r--r--generic/Image.cpp86
-rw-r--r--generic/Input.cpp70
-rw-r--r--generic/Output.cpp68
-rw-r--r--generic/String.cpp358
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;
+}