summaryrefslogtreecommitdiff
path: root/doc/API
blob: de5c555326ae60833b0d52ed03ac2dbbd6d8a576 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
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 <Main.h>

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 return 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("data.paq");

This one will "register" the archive named "data.paq". So, after that, if you
create an Input handle, it will first look into the archive data.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.