Baltisot API ~~~~~~~~~~~~ Class Base: ---------- Every single class should at last derives from this class. It override most of the memory usage functions. Here is the list of the functions I did override: strdup malloc realloc calloc operator new operator delete free pipe fork exit I did write some little and stupid memory functions. Maybe I'll later use dlmalloc or something like this. The other function will throw an exception if something goes wrong. If you can't write an inner-class function that has to allocate memory, use the x* functions: xstrdup xmalloc xrealloc xcalloc xfree xpipe xfork Also, in the base class, you'll find the "printm" function, which is a little tribute to help you printing things on the screen "ala" printf, but using the class String instead. The first argument is the class of the message, and can be M_BARE, M_ERROR, M_STATUS, M_WARNING, or M_INFO. The default verbosity level is to M_ERROR, and can be changed up to M_INFO. Class GeneralException: ---------------------- This is the generic exception that should be thrown by everything. And then the "main" program will act consequently. In order to help you writing the main function, some classes and macro have been defined. See below. Class derivated from GeneralException: ------------------------------------- We have the class MemoryException that will especially throw messages about Memory allocations problems. The class IOGeneral will be thrown for every problem about IO in general. The IOException is to be thrown by read & write when problems occurs. The IOAgain is thrown only when the Handle which is written or read is full and set to be non blocking. The last exception, TaskSwitch, will be thrown by every task that want to be suspended. You can inspire yourself from this class system to implements yours. Class Main: ---------- This is a pure virtual class that should be derivated in order to properly write the startup of a software of your own. To make it simple, you should write a software using this scheme: #include CODE_BEGINS virtual int startup() throw (GeneralException) { printm(M_BARE, "Hello world!\n"); } CODE_ENDS Class String: ------------ A very big class that can handle a large bunch of functions. Countrary of the STL's string class, this one is a "over everything" one. As much as possible, a String will be created. Here is the list of the constructs: String() creates an empty string. String(const String &) copy another string safely. String(const char *) copy the specified pointer into the string. String(char) creates a one-char string. String(int) creates a string containing the string representation of the int. String(unsigned int) same with an unsigned int. String(long long) same with a long long. String(unsigned long long) same with an unsigned long long. String(double) same with a double. Now to list of the methods. const char * set(const char *, ...) and const char * set(const String &, ...) They are the same as a sprintf functions, by changing the contents of the string. They return the temporary buffer used to create the string. Beware, it is constant, and there is a max size. If it exceeds, the result will be truncated. int scanf(const char *, ...) and int scanf(const String &, ...) They are the same as sscanf functions, and will read the contents of the string in order to fill the arguments given. const char * to_charp(size_t start = 0, ssize_t end = -1) const; It will copy the string into a temporary buffer. Beware, it is the same as the set function. The use of this function is depreciated. The arguments start and end specify two offsets of extraction into the string. If end == -1, then the whole string from the start offset will be copied. String extract(size_t start = 0, ssize_t end = -1) const; It will do the same as the to_charp function, but it will returns a String. Yet this function is not really good since it does call to_charp. But I'll translate it later with a better one. char * strdup(size_t = 0, ssize_t end = -1) const; This will produce a char *, still using the "not so good" extract function. I will clean the extract function, I swear. int to_int() const; Tries to convert the String into an int. If the string is *exactly* not an int, it will returns 0. Even " 123" will be rejected. double to_double() const; The same with a double. String to_sqdate() const; This is a weired fonction that will convert the string "JJ/MM/AAAA" to "AAAAMMJJ". String to_sqltime() const; The same between "h:m" to the number h * 60 + m. String from_sqldate() const; String from_sqltime() const; Those two function will revert to the original strings. Well the four above functions are weired, but sometime useful. double datedif(const String &) const; This will compute the number of days between the two dates. One can be the string "today". This code is located into the file 'datedif.c' written by Micael Widell. Check into the file for copyright details. bool is_date() const; bool is_number() const; bool is_float() const; bool is_time() const; These four fonctions will check if the string is actually a date, a number (int), a float(well double too) and a time. size_t strlen() const; Returns the length of the string. The function is immediate because it is stored into the object. ssize_t strchr(char c, size_t start = 0) const; Looks and return the first offset for a given char into a string. It will look from the given start point. Returns -1 if the char is not found. ssize_t strrchr(char c) const; Look and return the last offset for a given char into a string. Returns -1 if not found. ssize_t strstr(const String & str) const; It will returns the position of the string str, or -1 if not found. int strchrcnt(char c) const; It will count the number of time of the char c into the string. String & operator=(const String &); Only to be safe. Well, it will safely assign one string to another. Also safe to do s = s. String operator+(const String &) const; Concatens two strings to another third. String & operator+=(const String &) const; Add one string to the end. bool operator!=(const String &) const; bool operator==(const String &) const; bool operator<=(const String &) const; bool operator>=(const String &) const; bool operator<(const String &) const; bool operator>(const String &) const; The classical comparator fonctions. This will use strcmp so the meaning is the same. They are case sensitive. Maybe I will add a function to switch to case unsensitive with a global variable. char operator[](size_t i) const; Extract one char from the string. Like the classical char * does. Well, it will returns 0 if over the size of the string. One note: since you can construct a String with a char * or basically everything else, you can write things like: String s = String("Pim ") + "pam " + "poum."; Just use your imagination. I also overloaded the two operators << and >> for *stream: ostream & operator<<(ostream &, const String &); istream & operator>>(istream &, String &); They act as the Handles read and write function, so take a look at them. Class Regex: ----------- Well, to use this class, please read a bit the regex(7) man page. You have two construct: Regex(const String & regex, int cflags = REG_EXTENDED, int eflags = 0) Regex(const Regex &); The first construct gets its meaning from the regex man page. The cflag REG_NOSUB will always be applied. The second one is the classical copy-construct. You can match a regex against a string using: bool Match(const String &) const; which will return true if the string matches the regex, and false otherwise. The construct may throw a GeneralException in case of compilation error. There is two global regex: any and empty. any.match(s) will always be true, and empty.match(s) will be true if s == "". Class Variables: --------------- Somewhat weired class. I designed it especially for the HttpServ class to handle the POST variables strings. But you can use it for your own purpose. The construct Variables(int n = 0); will initiate a stack of n empty variables. You can then use these methods: For the methods, one variable is in the shape: "Name=value" void SetTo(int i, const String & s); This will set the ith variables. String operator[](const String & s); This will returns the value of one variable name String operator[](int i); This will returns the ith variable. void Dump(Handle *, const String & format = ""); This will dump the variables stack to the Handle. Especially designed to be used for the HttpServ. The format string is not yet usable. int GetNb(); Returns the number of variables into the stack. void Add(const String &); Adds a new variable at the end of the stack. void Del(int); Deletes the ith variable. void Del(const String &); Deletes the variable given to his name. class Handle: ------------ This class is a base one to be derivated into others. Here is the list of the constructs: public construct: Handle(const Handle &); The per-copy construct will duplicate the handle. If you close one, the other will remains open. But beware, it will only works for childrens. You can't create an "empty" Handle from your own. protected construct: Handle(int h); Only for childs. Used to fill the structure. virtual ssize_t read(void *buf, size_t count) throw (GeneralException); virtual ssize_t write(const void *buf, size_t count) throw (GeneralException); Self explainatory. Will never "fail" so the ssize_t type is only here for compatibility. It will throw an exception instead. But it still can return a smaller size than asked. Uint8 readU8(); Uint16 readU16(); Uint32 readU32(); void writeU8(Uint8); void writeU16(Uint16); void writeU32(Uint32); Some very important functions. They will always work in little endian. Even if the machine is big endian. So on a big endian machine, it will swap the bytes. bool IsClosed(void); Returns true if the stream is closed. The stream will self close if it does "forcibilly" hit end of file. Meaning that if you already are at the end of the file and still try to read something, it will return you a zero void SetNonBlock(void); Set the handle non blocking. Will be *VERY* useful for the Task system. bool IsNonBlock(void); Returns true if the handle has been set non blocking. virtual bool CanRead(); True if the handle can read. virtual bool CanWrite(); True if the handle can write. virtual bool CanSeek(); True ie the handle can seek. virtual off_t seek(off_t, int = SEEK_SET) throw (GeneralException); Will work exactly as the fseek() function. Even using the same arguments. virtual off_t tell() const; Will work as the ftell() function. virtual String GetName(); The actual name of the Handle. virtual off_t GetSize(); The size of the input opened file. -1 if not possible to get the size. virtual time_t GetModif(); Get the modification time of the file if possible. void close() throw (GeneralException); Closes the handle. int GetHandle(); This will get the handle number. Usage depreciated but sometime necessary. virtual bool CanWatch(); True if the handle can be watched (when non blocking) virtual int Dup() const; Act exactly as the dup() function. virtual void SetZ(int level) throw (GeneralException); Set the Handle to go through libz. Compress will occurs if write() and decompress will occurs if read(). Level between 0 and 9 sets the compression ratio. SetZ(0) will do nothing. You can't revert to SetZ(0) after SetZ to a non zero level. Also, will only works for unidirectionnal streams. I've got two operators: Handle & operator<<(Handle &, const String &); Handle & operator>>(Handle &, String &); who works the same as the String >> and << operators. When <<, the string will be dumped as exactly. When >>, the string will be readed until \n or eof. The char \r is discarded. The char \n, if reached, is not stored. A little helper function: void copy(Handle * src, Handle * dst, ssize_t count = -1); It will copy one whole Handle to another or only count bytes if >= 0 Class Input: ----------- Derivated from the Handle class. Not much to say using bare... The construct takes the file name to open. Just watch for an IOGeneral exception, to catch a file not found for example. A better thing to know is the following class... Class Archive: ------------- This class will handle some kinds of archives types. Actually, it only handles "proprietary" NPAQ files. Look at the source code if you want to know the format. A helper piece of software is here to help you compressing a directory into a .paq file. Here is how you use it: First you create a variable of type "Archive", like this: new Archive("datas.paq"); This one will "register" the archive named "datas.paq". So, after that, if you create an Input handle, it will first look into the archive datas.paq to see if your file is not in. It will only do so if the file path is relative (ie not begining with '/' or with '?:\' (for windows...)) If your file is found in the archive, it will be read directly and transparantly. Otherwise, it will be a normal Input handle. Class Stdin_t: ------------- Designed to create the Stdin object. You can use it to input from the stdin. This will works even if the stdin was redirected AFTER the start of the main() function. Every Stdio_t object that will be instancied will be a dup from the current stdio and remains as it. Class Output: ------------ Derivated from the Handle class. Exactly as the Input class, not much to say. Class Stdout_t & Stderr_t: ------------------------- Exactly like the Stdin_t, and the Stdout & Stderr are the names of the global objects that you can use. Class Buffer: ------------ A virtual Handle that writes everything into a growing buffer. Very useful. You can even assign one buffer to another with the operator =. Should be overflow proof. Class InPipe: ------------ This class is designed to hook stdout. When a further process will write to stdout, the result will be read into the InPipe created, if it has been hooked with the method Hook(). Designed to Hook only after a fork(). Class OutPipe: ------------- The same but with stdin. You writes to the OutPipe, and the child process will read it into stdin. Class Socket: ------------ A merly complete class designed to be used on top of every socket using function. You have the following functions: bool SetLocal(const String & vhost, int port); It will bind the vhost and / or the port to the socket, and return true if binded. bool Connect(const String & host, int port); It will connect to the specified host / port, and return true if successful, using the vhost if binded, and local port if binded. bool Listen(); It will begin to listen to the binded vhost and / or port, and return true if successful. Socket Accept() throw (GeneralException); It will wait and return the socket of an incoming connection. bool IsConnected(); bool IsListening(); Self explanatory. int GetPort(); Will return the port binded to a non-previously binded Listening socket. Class IRC: --------- Not yet workable. Class TaskMan: ------------- This is a static class that will manage all the task created. The only general purpose of this class is to run the MainLoop() function. The Task itself will never really call any function of the TaskMan. Everything is located into the base class Task. Class Task: ---------- Only designed to be derivated. Let me introduce it, it's my little baby. It's not yet really finished but I'll end it soon. Each task has an internal state. It can be TASK_ON_HOLD, the default when created, TASK_DONE, when the task has finished its work, and TASK_BURST. When you design a Task, you should always have some virtual functions: virtual String GetName(); That will return a canonical name for the task. virtual int Do() throw (GeneralException); That will process a "chunk" of things to do. The execution time of Do() should be reasonable. You design it as you wish but if it does block or last a very long time, the tasking system won't work. You can ask the TaskMan to "wake up" your task from some events. The only events working are the WaitFor(Task *) and WaitFor(Handle *). In the future there will be WaitFor(pid_t) and WaitFor(timeout). To "record" the internal process state of the method Do(), you have the protected variable 'current' that is defaulted to 0 at start time. With that, I encourage you to design your Do() function like this: switch(current) { case 0: /* do some work */ WaitFor(something); current = 1; Suspend(); case 1: /* continue your work */ WaitFor(something_else); current = 2; Suspend(); case 2: ... } If you return from the Do() function, you have to specify the state you want, from TASK_ON_HOLD (default), TASK_DONE (task finished) and TASK_BURST. TASK_BURST will say that at the next loop, the task should be launched even with no events. But you should then create yourself an event because if you don't, the burning task will overheat the TaskMan. The purpose of the TASK_BURST is to add events that was not able to be created during the creating of the object, or when a Task wants to signal something to another, it sets it to TASK_BURST using the SetBurst() method. GetState() will tells you the current state of your Task. A task can be Stop()ed or Restar()ed, and its state of pause can be given by IsStopped(). Each task declares itself to the TaskMan, and if not WaitedBy() another task (Using the WaitFor(task) watches) it will be deleted when its state goes TASK_DONE. If not, it will remains zombie until the father task deletes it. The Suspend() function will act like a return GetState(). The only differences is that it is done by throwing an exception, so that you can call Suspend from within another method. You can also specify the new state by giving it as argument of Suspend(). About the WaitFor() functions. The WaitFor(Task) is really simple. It will makes the TaskMan to call the Do() function when the specified task has ended. The waiting function HAS to delete the zombie. The WaitFor(Handle) accepts a flag. It is a | of the following flags: W4_READING, W4_WRITING, W4_STICKY. In all cases the task will be awoken if something bad happends to the handle. When a watch over a Handle occures, the watch is removed, unless W4_STICKY. A task can do anythings it wants, especially causing a GeneralException. Then it will ended by the TaskMan, like if it did return TASK_DONE. Well I hoped I was enough clear. If not, read the source code of the following classes: Class CopyJob: ------------- This task takes four parameters as constructor: CopyJob(Handle * s, Handle * d, ssize_t max = -1, bool ds = false); The task will copy the handle s to the handle d. If max != -1 then it will copy at most max bytes. If the bool ds is true, then the source will be deleted when done. Not much to say. Very very very useful. Works binarly. Class ReadJob: ------------- ReadJob(Handle * s, Handle * d, const Regex & regex = empty); This task will read the source handle and write the result to the destination handle line by line, until a line matches the regex. The matching line will also be copied. Class HttpServ: -------------- This class is a task that can be launched from the main function, and will never end. It is specially designed to create distributed applications.