124 changed files with 12807 additions and 0 deletions
-
0AUTHORS
-
51ChangeLog
-
27Makefile.am
-
65NEWS
-
0README
-
45autoclean.sh
-
15autogen.sh
-
168configure.ac
-
BINdesign/scot-event-subsystem.dia
-
102event_new.c
-
47include/Makefile.am
-
117include/scot/cmdla.h
-
26include/scot/dir_common.h
-
106include/scot/event.h
-
53include/scot/event_listener.h
-
52include/scot/excenv_t.h
-
133include/scot/exception.h
-
68include/scot/exception_t.h
-
47include/scot/fs_watcher.h
-
31include/scot/inotify.h
-
64include/scot/list.h
-
214include/scot/list_func_proto.h
-
252include/scot/list_impl.h
-
382include/scot/list_man.h
-
308include/scot/list_mod.h
-
290include/scot/list_nav.h
-
101include/scot/list_proto.h
-
64include/scot/list_type_proto.h
-
71include/scot/posix/dir.h
-
32include/scot/posix/memory.h
-
9include/scot/posix/scot_types.h
-
102include/scot/posix/thread.h
-
69include/scot/queue.h
-
89include/scot/queue_func_proto.h
-
241include/scot/queue_impl.h
-
68include/scot/queue_proto.h
-
61include/scot/queue_type_proto.h
-
19include/scot/scot_exceptions.h
-
85include/scot/socket.h
-
15include/scot/socket_in.h
-
14include/scot/socket_un.h
-
69include/scot/stack.h
-
89include/scot/stack_func_proto.h
-
239include/scot/stack_impl.h
-
68include/scot/stack_proto.h
-
61include/scot/stack_type_proto.h
-
132include/scot/stream.h
-
72include/scot/stream_pool.h
-
53include/scot/stream_pool_fraction.h
-
8include/scot/stream_win.h
-
51include/scot/thread_none.h
-
44include/scot/win32/dir.h
-
40include/scot/win32/memory.h
-
6include/scot/win32/scot_types.h
-
79include/scot/win32/thread.h
-
98include/scot_common.h
-
1m4/Makefile.am
-
685m4/ax_create_stdint_h.m4
-
61src/Makefile.am
-
408src/cmdla.c
-
348src/event.c
-
157src/event_listener.c
-
157src/event_manager.c
-
79src/event_subsys/event-subsys.txt
-
0src/event_subsys/scot_dispatch_manager.c
-
0src/event_subsys/scot_dispatcher.c
-
3src/event_subsys/scot_event_sink.c
-
0src/event_subsys/scot_event_typ.c
-
0src/event_subsys/scot_event_typ_GTK
-
0src/event_subsys/scot_event_typ_OPENGL
-
0src/event_subsys/scot_event_typ_SDL
-
0src/event_subsys/scot_event_typ_manager.c
-
0src/event_subsys/scot_event_typ_mswin.c
-
0src/event_subsys/scot_event_typ_xwin.c
-
868src/exception.c
-
416src/fs_watcher.c
-
340src/list.c
-
1src/po/LINGUAS
-
41src/po/Makevars
-
4src/po/POTFILES.in
-
BINsrc/po/de.gmo
-
171src/po/de.po
-
165src/po/scot.pot
-
1src/po/stamp-po
-
136src/posix/dir.c
-
133src/posix/spf_thread_impl.c
-
44src/posix/stream_ctl.c
-
169src/posix/thread.c
-
46src/queue.c
-
33src/scot_common.c
-
60src/scot_exceptions.c
-
184src/socket.c
-
200src/socket_in.c
-
149src/socket_un.c
-
47src/stack.c
-
189src/stream.c
-
328src/stream_pool_base.c
-
154src/stream_pool_fraction.c
-
245src/stream_pool_management.c
-
16src/stream_win.c
@ -0,0 +1,51 @@ |
|||||
|
2006-08-17 Georg Steffers [GST] <georg@steffers.org> |
||||
|
|
||||
|
* src/stream_pool.c src/posix/stream_pool.c src/win32/stream_pool.c |
||||
|
include/stream_pool.h include/posix/stream_pool.h |
||||
|
include/win32/stream_pool.h src/Makefile.am include/Makefile.am |
||||
|
and various others (this is a major change): |
||||
|
Sorry, this is in german and much to declarative...this was a |
||||
|
thoughts-list that is now realized completely. I will rewrite it when |
||||
|
i find the time. |
||||
|
|
||||
|
OK, ich fang mal wieder damit an meine Gedanken aufzunehmen. |
||||
|
Das Problem das ich jetzt bekomme ist, das es streams unter |
||||
|
windows nicht gibt...bzw. verschieden arten von streams unterschiedlich |
||||
|
gehandhabt werden müssen. Hinzu kommt, das WaitForMultipleObject |
||||
|
nur max. 64 Objekte werwalten kann. Will man mehr verwalten muß man |
||||
|
das in mehreren streads tun. |
||||
|
|
||||
|
Daher muß ein stream_pool, anders als andere event listener nicht |
||||
|
nur aus einem thread bestehen sondern aus einem pro 64 gleicher |
||||
|
streams und einem Kontoll-Thread. (Hmm, für viele andere event listener |
||||
|
gilt das gleiche, wenn ich unter Windows mehr als 64 Objekte |
||||
|
überwachen will. z.B. der fs_watcher. Gerade beim fs_watcher ist |
||||
|
es aber nun so, daß der unter Windows eh komplett anders |
||||
|
geschrieben werden muß.) |
||||
|
|
||||
|
Startet man einen stream_pool_listener, so wird der Kontroll Thread |
||||
|
gestartet, welcher seinerseits alle weiteren threads startet. |
||||
|
|
||||
|
Added man einen stream, so muß zunächst nachgesehen werden ob es |
||||
|
bereits einen <<stream pool>> für diesen stream_type gibt der außerdem |
||||
|
noch nicht 64 streams enthält, falls es so einen stream pool gibt |
||||
|
kann man den stream zu diesem hinzufügen, anderenfalls muß ein |
||||
|
neuer stream pool angelegt werden. |
||||
|
Nachdem der stream geadded wurde muß nur der stream pool, zu dem |
||||
|
der stream hinzugefügt wurde neu gestartet werden. |
||||
|
|
||||
|
Will man einen stream aus einem stream pool entfernen, so muß dieser |
||||
|
zunächst in allen stream pools gesucht werden, dann muß der thread |
||||
|
zu dem stream pool in dem sich der stream befindet gestoppt werden |
||||
|
woraufhin der stream entfernt werden kann. Danach muß der stream pool |
||||
|
thread wieder gestartet werden. |
||||
|
|
||||
|
Für UNIX brauche ich nur einen einzige thread methode für alle stream |
||||
|
pool typen, nämlich die, welche select nutzt. |
||||
|
Für Windows muß ich je nach dem welcher Art von streams ein stream pool |
||||
|
enthält unterschiedliche thread methoden nutzen: |
||||
|
- select für sockets |
||||
|
- WaitForMultipleObject für andere (Wie stell ich dabei fest was genau |
||||
|
mit dem Objekt passiert ist? OK, für pipes ist das Einfach, da es |
||||
|
eh ein Wege Kommunikation ist.) |
||||
|
- und möglicherweise noch andere. |
||||
@ -0,0 +1,27 @@ |
|||||
|
DEFS = -DHAS_CONFIG @DEFS@ |
||||
|
|
||||
|
ACLOCAL_AMFLAGS = -I m4 |
||||
|
|
||||
|
EXTRA_DIST = config/config.rpath config/mkinstalldirs \
|
||||
|
include/scot_common.h \
|
||||
|
include/scot/stream_pool_fraction.h \
|
||||
|
include/scot/win32/thread.h \
|
||||
|
include/scot/win32/memory.h \
|
||||
|
include/scot/win32/dir.h \
|
||||
|
include/scot/win32/scot_types.h \
|
||||
|
include/scot/posix/thread.h \
|
||||
|
include/scot/posix/memory.h \
|
||||
|
include/scot/posix/dir.h \
|
||||
|
include/scot/posix/scot_types.h \
|
||||
|
src/win32/thread.c \
|
||||
|
src/win32/dir.c \
|
||||
|
src/win32/memory.c \
|
||||
|
src/win32/spf_thread_impl.c \
|
||||
|
src/win32/stream_ctl.c \
|
||||
|
src/posix/thread.c \
|
||||
|
src/posix/dir.c \
|
||||
|
src/posix/spf_thread_impl.c \
|
||||
|
src/posix/stream_ctl.c \
|
||||
|
design/scot-event-subsystem.dia |
||||
|
|
||||
|
SUBDIRS = m4 include src src/po test test/po |
||||
@ -0,0 +1,65 @@ |
|||||
|
2006-08-07 |
||||
|
Es gibt noch einen bug im exception handling. Ich kann im Moment noch |
||||
|
nicht genau sagen was passiert, evtl. ist es auch nur ein bug im testprogramm. |
||||
|
Jedenfalls bekomme ich eine Fehlermeldung von wegen THROW kann nur in |
||||
|
einem TRY-CATCH block aufgerufen werden wenn der stream_pool thread mit |
||||
|
exit beendet. |
||||
|
Ich weiß zur Zeit noch nicht ob dieser Fehler im Hauptthread oder im |
||||
|
stream_pool thread passiert, ich vermute aber im Hauptthread, da der |
||||
|
CATCH-Bereich des stream_pool threads ausgeführt wird. |
||||
|
|
||||
|
Möglicherweise ist das aber auch ein genereller Bug im exception system, |
||||
|
der auftritt sobald man exit () in einem catch bereich nutzt. (Was eigentlich |
||||
|
auch nicht wirklich ne gute Idee ist (meistens jedenfalls)...trotzdem sollte |
||||
|
es möglich sein. im zweifelsfall durch eine eigene Funktion exc_exit oder so. |
||||
|
|
||||
|
OK, der richtige excenv stack sollte selectiert werden...daran liegts nicht. |
||||
|
Trotzdem scheint es kein excenv mehr in diesem stack zu geben nachdem ich |
||||
|
in den CATCH Block von scot_stream_pool_main_loop gekommen bin. |
||||
|
|
||||
|
AHA, die event_listener_fini methode throwed evtl. eine exception, und zwar |
||||
|
ganau dann wenn sie von ihrem eigenen main loop aufgerufen wurde. Was |
||||
|
hier passierte...allerdings schon aus dem CATCH Teil der main_loop |
||||
|
methode, wodurch kein excenv mehr da war. |
||||
|
Nachdem ich einen TRY-CATCH Block um den betreffenden Teil in |
||||
|
event_listener_fini gemacht habe war das Problem behoben. |
||||
|
|
||||
|
-------------------- |
||||
|
|
||||
|
Der fs_watcher code funktioniert so nicht. Man kann von dem notify descriptor |
||||
|
leider nicht genau so lesen wie von einem file descriptor. |
||||
|
Ich werde also code in scot stream integrieren, der die besonderheiten |
||||
|
von inotify descriptoren berücksichtigt. |
||||
|
Schließlich soll scot stream genau für sowas eine abstraction liefern. |
||||
|
|
||||
|
-------------------- |
||||
|
|
||||
|
2006-08-23 |
||||
|
|
||||
|
OK, fs-watcher mit inotify functioniert gröstenteils. Das heißt auf einer |
||||
|
single cpu maschine läuft es problemlos, auf meiner alten SMP Maschine kommt |
||||
|
der thread der die filesystem events überwacht ab und zu irgendwie in einen |
||||
|
busy loop oder so was, jedenfalls reagiert er nicht mehr und zieht nahezu |
||||
|
100% CPU time auf einer CPU. |
||||
|
|
||||
|
--------------------- |
||||
|
|
||||
|
Und hier jetzt der Knüller des Jahrhunderts. |
||||
|
### select von winsock2 ist kein cancellation point ### |
||||
|
### und (noch besser) kann nicht unterbrochen werden ### |
||||
|
Unerwartete und nervig. Seit Winsock2 ist select nicht mehr unterbrechbar. Das |
||||
|
macht es quasi unbrauchbar für threads wenn diese von Zeit zu Zeit unterbrochen |
||||
|
werden sollen (z.B. damit der select in dem thread neu hinzugekommene |
||||
|
Verbindungen mit überwacht), es sei denn man setzt die threads in einen |
||||
|
asynchronous mode. |
||||
|
Außerdem nuss ich multiple threads für die socket verwaltung verwenden, da |
||||
|
windows select per default nur 64 sockets verwalten kann, was für einen server |
||||
|
geradezu lächerlich wenig ist, also benutze ich pro 64 sockets einen thread. |
||||
|
Im Moment suche ich nach einem Weg wie ich das Problem umgehen kann. Eine gute |
||||
|
Möglichkeit scheint zu sein, den socket an dem ich auf connections warte auch |
||||
|
in jedem select zu überwachen, dann sollte der select zurückkommen sobald eine |
||||
|
neue Verbindung hergestellt wird. |
||||
|
Dann muß nur noch sichergestellt sein das sich nur ein thread um die neu |
||||
|
ankommende Verbindung kümmert und das alle anderen solange warten bis der neue |
||||
|
socket in die zuständige socketliste eingetragen wurde. Das sollte aber mit |
||||
|
einer critical section kein Problem sein. |
||||
@ -0,0 +1,45 @@ |
|||||
|
#!/bin/sh |
||||
|
# Script for cleaning all autogenerated files. |
||||
|
|
||||
|
test ! -f Makefile || make distclean |
||||
|
|
||||
|
# Brought in by autopoint. |
||||
|
rm -f ABOUT-NLS |
||||
|
mv m4/ax_create_stdint_h.m4 . |
||||
|
rm -f m4/*.m4 |
||||
|
mv ax_create_stdint_h.m4 m4 |
||||
|
rm -f src/po/Makefile.in.in |
||||
|
rm -f src/po/remove-potcdate.sin |
||||
|
rm -f test/po/Makefile.in.in |
||||
|
rm -f test/po/remove-potcdate.sin |
||||
|
|
||||
|
# Generated by aclocal. |
||||
|
rm -f aclocal.m4 |
||||
|
|
||||
|
# Generated by autoconf. |
||||
|
rm -f configure |
||||
|
|
||||
|
# Generated by autoheader |
||||
|
rm -f config.h.in |
||||
|
|
||||
|
# Generated or brought in by automake. |
||||
|
rm -f Makefile.in |
||||
|
rm -f m4/Makefile.in |
||||
|
rm -f src/Makefile.in |
||||
|
rm -f test/Makefile.in |
||||
|
rm -f include/Makefile.in |
||||
|
rm -f INSTALL |
||||
|
rm -f COPYING |
||||
|
|
||||
|
# Generated by all in config |
||||
|
rm -rf config |
||||
|
|
||||
|
rm -rf autom4te.cache |
||||
|
|
||||
|
# Generated by testruns |
||||
|
find . -name exc_test.fil -exec rm -f {} \; |
||||
|
|
||||
|
# Generated by doxygen |
||||
|
rm -f doxy.wrn |
||||
|
rm -rf doc/full/* |
||||
|
rm -rf doc/usage/* |
||||
@ -0,0 +1,15 @@ |
|||||
|
#!/bin/sh |
||||
|
# Script for regenerating all autogenerated files. |
||||
|
|
||||
|
autopoint -f # was: gettextize -f -c |
||||
|
cp po/Makefile.in.in src/po |
||||
|
cp po/remove-potcdate.sin src/po |
||||
|
cp po/Makefile.in.in test/po |
||||
|
cp po/remove-potcdate.sin test/po |
||||
|
rm -fR po |
||||
|
|
||||
|
aclocal -I m4 |
||||
|
autoconf |
||||
|
autoheader |
||||
|
libtoolize -c -f |
||||
|
automake -a -c |
||||
@ -0,0 +1,168 @@ |
|||||
|
AC_PREREQ(2.59) |
||||
|
AC_INIT(scot, 0.0.3, BUG-REPORT-ADDRESS) |
||||
|
AC_CONFIG_AUX_DIR([config]) |
||||
|
AC_CONFIG_SRCDIR([src/cmdla.c]) |
||||
|
AC_CONFIG_HEADER([config.h]) |
||||
|
AM_INIT_AUTOMAKE |
||||
|
|
||||
|
AC_CANONICAL_HOST |
||||
|
|
||||
|
# Checks for programs. |
||||
|
AC_PROG_CC |
||||
|
AC_PROG_MAKE_SET |
||||
|
AC_LIBTOOL_WIN32_DLL |
||||
|
AC_PROG_LIBTOOL |
||||
|
|
||||
|
# Checks for header files. |
||||
|
AC_HEADER_STDC |
||||
|
AC_CHECK_HEADERS([getopt.h libintl.h locale.h stdlib.h string.h unistd.h wchar.h]) |
||||
|
AX_CREATE_STDINT_H([include/scot/scot_int.h]) |
||||
|
|
||||
|
|
||||
|
# Checks for libraries. |
||||
|
AM_GNU_GETTEXT([external]) |
||||
|
AC_MSG_CHECKING([intl]) |
||||
|
AC_MSG_RESULT([$LIBINTL]) |
||||
|
AM_GNU_GETTEXT_VERSION(0.13.1) |
||||
|
localedir=`eval echo $datadir/locale` |
||||
|
AC_DEFINE_UNQUOTED(LOCALEDIR, "$localedir", [Name of gettext locale directory]) |
||||
|
THREAD_LIB= |
||||
|
THREAD_CFLAGS= |
||||
|
AC_MSG_CHECKING([for Win32]) |
||||
|
case "$host" in |
||||
|
*-*-mingw*) |
||||
|
win32="yes, use windows threads" |
||||
|
pthread="pthreadGC2" |
||||
|
SOCK_LIB="-lws2_32" |
||||
|
;; |
||||
|
*) |
||||
|
win32="no" |
||||
|
pthread="pthread" |
||||
|
SOCK_LIB="" |
||||
|
;; |
||||
|
esac |
||||
|
AC_MSG_RESULT([$win32]) |
||||
|
|
||||
|
AC_CHECK_LIB($pthread,pthread_create, |
||||
|
THREAD_LIB=-l$pthread |
||||
|
THREAD_CFLAGS="-DUSE_PTHREAD -DREENTRANT" |
||||
|
thread="PTHREAD", |
||||
|
THREAD_CFLAGS="-DUSE_WTHREAD" |
||||
|
thread="WTHREAD",) |
||||
|
|
||||
|
AC_SUBST(SOCK_LIB) |
||||
|
AC_SUBST(THREAD_LIB) |
||||
|
AC_SUBST(THREAD_CFLAGS) |
||||
|
|
||||
|
AM_CONDITIONAL(USE_THREADS, test "x$thread" != "x") |
||||
|
AM_CONDITIONAL(PTHREAD, test "x$thread" == "xPTHREAD") |
||||
|
AM_CONDITIONAL(WTHREAD, test "x$thread" == "xWTHREAD") |
||||
|
AM_CONDITIONAL(WIN32, test "x$win32" != "xno") |
||||
|
|
||||
|
# Checks for typedefs, structures, and compiler characteristics. |
||||
|
AC_C_CONST |
||||
|
|
||||
|
# Checks for library functions. |
||||
|
AC_CHECK_FUNCS([memset setlocale]) |
||||
|
|
||||
|
dnl We need to check if the right inotify version is accessible |
||||
|
use_inotify="yes" |
||||
|
AC_MSG_CHECKING([whether inotify is to be used for filemonitoring]) |
||||
|
|
||||
|
if test "x$win32" == "xno" |
||||
|
then |
||||
|
AC_ARG_ENABLE(inotify, |
||||
|
[ --disable-inotify disable inotify in the ecore_file module], |
||||
|
[ |
||||
|
if test "$enableval" == "yes"; then |
||||
|
AC_MSG_RESULT([yes]) |
||||
|
else |
||||
|
AC_MSG_RESULT([no - but we need it]) |
||||
|
use_inotify="no" |
||||
|
fi |
||||
|
], [ |
||||
|
AC_MSG_RESULT([yes]) |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
dnl It's hard to find a good test on how to check the correct |
||||
|
dnl inotify version. They changed the headers a lot. |
||||
|
dnl in kernel 2.6.13 __NR_inotify_init was added to the defined syscalls |
||||
|
dnl in asm/unistd.h and IN_MOVE_SELF was added to linux/inotify.h |
||||
|
dnl so with this check you need a very new kernel and kernel-headers! |
||||
|
dnl On my gentoo, /usr/include/asm and /usr/include/linux are no symlinks |
||||
|
dnl into the current kernel tree....so i also try to find the includes |
||||
|
dnl under /usr/src/linux or under /usr/include/linux-`uname -r` |
||||
|
linux_rev=`uname -r` |
||||
|
INOTIFY_INCLUDES= |
||||
|
AC_MSG_CHECKING([for sufficient inotify includes]) |
||||
|
if test "x$use_inotify" = "xyes"; then |
||||
|
AC_TRY_COMPILE( |
||||
|
[ |
||||
|
#include <asm/unistd.h> |
||||
|
#include <linux/inotify.h> |
||||
|
], |
||||
|
[ int a = __NR_inotify_init; int b = IN_MOVE_SELF; ], |
||||
|
[ |
||||
|
AC_DEFINE(HAVE_INOTIFY, 1, [ File monitoring with Inotify ]) |
||||
|
an_inc=/usr/include |
||||
|
], |
||||
|
[ |
||||
|
AC_TRY_COMPILE( |
||||
|
[ |
||||
|
#include "/usr/src/linux/include/asm/unistd.h" |
||||
|
#include "/usr/src/linux/include/linux/inotify.h" |
||||
|
], |
||||
|
[ int a = __NR_inotify_init; int b = IN_MOVE_SELF; ], |
||||
|
[ |
||||
|
AC_DEFINE(HAVE_INOTIFY, 1, [ File monitoring with Inotify ]) |
||||
|
AC_DEFINE(IN_KERNEL, 1, [ blablabla ]) |
||||
|
INOTIFY_INCLUDES=-I/usr/src/linux/include |
||||
|
an_inc=/usr/src/linux/include |
||||
|
], |
||||
|
[ |
||||
|
AC_TRY_COMPILE( |
||||
|
[ |
||||
|
#include </usr/src/linux-$linux_rev/include/asm/unistd.h> |
||||
|
#include </usr/src/linux-$linux_rev/include/linux/inotify.h> |
||||
|
], |
||||
|
[ int a = __NR_inotify_init; int b = IN_MOVE_SELF; ], |
||||
|
[ |
||||
|
AC_DEFINE(HAVE_INOTIFY, 1, [ File monitoring with Inotify ]) |
||||
|
AC_DEFINE(IN_KERNEL_UNAME, 1, [ blablabla ]) |
||||
|
INOTIFY_INCLUDES=-I/usr/src/linux-$linux_rev/include |
||||
|
an_inc=/usr/src/linux-$linux_rev/include |
||||
|
], |
||||
|
[ |
||||
|
use_inotify="no" |
||||
|
an_inc="not found" |
||||
|
] |
||||
|
) |
||||
|
] |
||||
|
) |
||||
|
] |
||||
|
) |
||||
|
AC_MSG_RESULT([$an_inc]) |
||||
|
test "x$an_inc" == "xnot found" && exit |
||||
|
else |
||||
|
AC_MSG_RESULT(["Not used"]) |
||||
|
fi |
||||
|
|
||||
|
AC_SUBST(INOTIFY_INCLUDES) |
||||
|
else |
||||
|
use_inotify="no" |
||||
|
AC_MSG_RESULT([no]) |
||||
|
fi |
||||
|
|
||||
|
AM_CONDITIONAL(USE_INOTIFY, test "x$use_inotify" != "xno") |
||||
|
|
||||
|
|
||||
|
AC_CONFIG_FILES([Makefile]) |
||||
|
AC_CONFIG_FILES([src/Makefile]) |
||||
|
AC_CONFIG_FILES([include/Makefile]) |
||||
|
AC_CONFIG_FILES([test/Makefile]) |
||||
|
AC_CONFIG_FILES([m4/Makefile]) |
||||
|
AC_CONFIG_FILES([src/po/Makefile.in]) |
||||
|
AC_CONFIG_FILES([test/po/Makefile.in]) |
||||
|
|
||||
|
AC_OUTPUT |
||||
@ -0,0 +1,102 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <scot/scot_int.h> |
||||
|
#include <scot/event.h> |
||||
|
#include <scot/thread.h> |
||||
|
|
||||
|
#define GEN_LOCAL |
||||
|
#include <scot/list.h> |
||||
|
#include <scot/queue.h> |
||||
|
#undef GEN_LOCAL |
||||
|
|
||||
|
struct scot_event_manager; |
||||
|
|
||||
|
struct scot_event_source |
||||
|
{ |
||||
|
struct scot_event_manager * manager; |
||||
|
unsigned int group; |
||||
|
THREAD_T sthr; |
||||
|
scot_event_source_entry_fptr event_source_thread_entry; |
||||
|
|
||||
|
int (*event_done_cb) (struct scot_event *); |
||||
|
}; |
||||
|
|
||||
|
/* |
||||
|
* das ist cool, mit folgender Struktur und der Tatsache das die registrierten |
||||
|
* callbacks in einer Instanz dieser Struktur und dann in einer liste |
||||
|
* gespeichert werden bedeutet, das ich mehrere callback zu einem event |
||||
|
* registrieren kann. Im moment würden diese dann in undefinierter |
||||
|
* Reihenfolge aufgerufen, sobald ein event auftaucht. |
||||
|
* Sobald der tree code fertig ist sollte man die callbacks in einem |
||||
|
* balanced b-tree speichern bei dem der key die event-nummer ist. |
||||
|
* Das würde die zugriffe auf die callbacks nochmal erheblich beschleunigen. |
||||
|
* Vorher könnte man sich überlegen callbacks sortiert einzufügen. |
||||
|
* (Warscheinlich würde das auch schon reichen, da callbacks normalerweise |
||||
|
* nur einmal zu beginn des Programms registriert werden und daher die |
||||
|
* insert-zeit nicht so relevant ist.) |
||||
|
*/ |
||||
|
struct scot_event_cb |
||||
|
{ |
||||
|
uint32_t event; |
||||
|
int (*cb) (struct scot_event *); /* wenn ein cb 0 zurückliefert werden |
||||
|
keine weiteren registrierten |
||||
|
callbacks zu diesem event ausgeführt, |
||||
|
sonst so lange bis keine weiteren |
||||
|
events vorliegen. */ |
||||
|
}; |
||||
|
typedef struct scot_event_cb scot_event_cb_t; |
||||
|
GEN_LIST (scot_event_cb_t); |
||||
|
|
||||
|
struct scot_event_sink |
||||
|
{ |
||||
|
struct scot_event_manager * manager; |
||||
|
unsigned int group; |
||||
|
uint32_t mask; |
||||
|
|
||||
|
list_scot_event_cb_t_node_t * cb_mappings; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
typedef struct scot_event scot_event_t; |
||||
|
GEN_QUEUE (scot_event_t); |
||||
|
|
||||
|
|
||||
|
struct scot_event_manager |
||||
|
{ |
||||
|
struct scot_event_source sources [32]; |
||||
|
struct scot_event_sink sinks [32]; |
||||
|
|
||||
|
queue_scot_event_node_t * queue; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* Funktionen zum manager |
||||
|
*/ |
||||
|
struct scot_event_manager * |
||||
|
scot_event_manager_new (void); |
||||
|
|
||||
|
int |
||||
|
scot_event_manager_register_source ( |
||||
|
struct scot_event_manager *, |
||||
|
struct scot_event_source *); |
||||
|
|
||||
|
int scot_event_manager_register_cb ( |
||||
|
struct scot_event_manager *, |
||||
|
uint32_t event, |
||||
|
int (*cb) (struct scot_event *)); |
||||
|
|
||||
|
/* |
||||
|
* Funktionen zur source |
||||
|
*/ |
||||
|
struct scot_event_source * |
||||
|
scot_event_source_init ( |
||||
|
unsigned int group, |
||||
|
int (*event_done_cb) (struct scot_event *)); |
||||
|
|
||||
|
int |
||||
|
scot_event_source_register ( |
||||
|
struct scot_event_source *); |
||||
|
|
||||
|
/* |
||||
|
* Funktionen zur sink |
||||
|
*/ |
||||
@ -0,0 +1,47 @@ |
|||||
|
nobase_include_HEADERS = scot/cmdla.h \
|
||||
|
scot/list.h scot/list_impl.h scot/list_proto.h \
|
||||
|
scot/list_man.h scot/list_mod.h scot/list_nav.h \
|
||||
|
scot/list_type_proto.h scot/list_func_proto.h \
|
||||
|
scot/stack.h scot/stack_impl.h scot/stack_proto.h \
|
||||
|
scot/stack_type_proto.h scot/stack_func_proto.h \
|
||||
|
scot/queue.h scot/queue_impl.h scot/queue_proto.h \
|
||||
|
scot/queue_type_proto.h scot/queue_func_proto.h \
|
||||
|
scot/exception.h scot/exception_t.h scot/excenv_t.h \
|
||||
|
scot/thread.h scot/memory.h scot/dir.h scot/dir_common.h \
|
||||
|
scot/scot_exceptions.h scot/scot_types.h \
|
||||
|
scot/socket.h scot/socket_in.h \
|
||||
|
scot/event.h scot/event_listener.h \
|
||||
|
scot/fs_watcher.h \
|
||||
|
scot/stream.h scot/stream_pool.h |
||||
|
|
||||
|
BUILT_SOURCES = scot/thread.h scot/memory.h scot/dir.h |
||||
|
CLEANFILES = scot/thread.h scot/memory.h scot/dir.h |
||||
|
|
||||
|
if PTHREAD |
||||
|
scot/thread.h: Makefile scot/posix/thread.h |
||||
|
cp scot/posix/thread.h scot/thread.h |
||||
|
else |
||||
|
scot/thread.h: Makefile scot/win32/thread.h |
||||
|
cp scot/win32/thread.h scot/thread.h |
||||
|
endif |
||||
|
|
||||
|
if WIN32 |
||||
|
nobase_include_HEADERS += scot/stream_win.h |
||||
|
|
||||
|
scot/scot_types.h: Makefile scot/win32/scot_types.h |
||||
|
cp scot/win32/scot_types.h scot/scot_types.h |
||||
|
scot/memory.h: Makefile scot/win32/memory.h |
||||
|
cp scot/win32/memory.h scot/memory.h |
||||
|
scot/dir.h: Makefile scot/win32/dir.h |
||||
|
cp scot/win32/dir.h scot/dir.h |
||||
|
else |
||||
|
nobase_include_HEADERS += scot/socket_un.h scot/inotify.h |
||||
|
|
||||
|
scot/scot_types.h: Makefile scot/posix/scot_types.h |
||||
|
cp scot/posix/scot_types.h scot/scot_types.h |
||||
|
scot/memory.h: Makefile scot/posix/memory.h |
||||
|
cp scot/posix/memory.h scot/memory.h |
||||
|
scot/dir.h: Makefile scot/posix/dir.h |
||||
|
cp scot/posix/dir.h scot/dir.h |
||||
|
endif |
||||
|
|
||||
@ -0,0 +1,117 @@ |
|||||
|
/* |
||||
|
* cmdla.h: Prototypes, defines, etc. for cmdla |
||||
|
* |
||||
|
* Copyright (C) 2006 Georg Steffers. All rights reserved. |
||||
|
* |
||||
|
* This software is licensed under the terms of the GNU Genral Public |
||||
|
* License (GPL). Please see gpl.txt for details or refer to |
||||
|
* http://www.gnu.org/licenses/gpl.html |
||||
|
* |
||||
|
* Author: Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* 01/14/2006: Georg Steffers - First implemented |
||||
|
* 01/15/2006: Georg Steffers - V0.1 ready. Modified this and that |
||||
|
* now long arguments are supported as |
||||
|
* well as arguments with am optional |
||||
|
* parameter. |
||||
|
* 01/23/2006: Georg Steffers - add support for gettext. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef CMDLA_H |
||||
|
#define CMDLA_H |
||||
|
|
||||
|
/* Datatypes of given commandline values */ |
||||
|
#define CMDLA_TYPE_STRING 0x00 |
||||
|
#define CMDLA_TYPE_INT 0x01 |
||||
|
#define CMDLA_TYPE_FLOAT 0x02 |
||||
|
|
||||
|
/* Indicates wether an arg requires an parameter or not */ |
||||
|
#define CMDLA_REQ_ARG 0x01 |
||||
|
#define CMDLA_OPT_ARG 0x02 |
||||
|
|
||||
|
#define CMDLAP_CBT_END { 0, NULL, 0, NULL, 0, NULL, NULL } |
||||
|
#define CMDLAS_CBT_END { 0, NULL, NULL, NULL, NULL } |
||||
|
|
||||
|
#define _GNU_SOURCE /* for getopt */ |
||||
|
|
||||
|
#include <unistd.h> |
||||
|
#include <wchar.h> |
||||
|
#include <getopt.h> |
||||
|
|
||||
|
#include <scot_common.h> |
||||
|
|
||||
|
/* |
||||
|
* This struct holds all neccesary infomation for the default |
||||
|
* usage callback. It is filled within process_cmd_line and used |
||||
|
* with any usage function that did not specify explicitly different |
||||
|
* behaviour. |
||||
|
*/ |
||||
|
struct du_infot |
||||
|
{ |
||||
|
const struct cmdlas_cbt *switches; |
||||
|
const struct cmdlap_cbt *arguments; |
||||
|
const char *about; |
||||
|
const char *copyright; |
||||
|
const char *usage_aa; |
||||
|
const char *program_name; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
typedef int (*cmdlap_cb) (const char *, const int, void *); |
||||
|
typedef int (*cmdlas_cb) (void *); |
||||
|
|
||||
|
/* |
||||
|
* CoMmanDLine Argument Parameter CallBack Type. |
||||
|
* This holds the definition of an argument that takes a parameter. |
||||
|
*/ |
||||
|
struct cmdlap_cbt { |
||||
|
char carg; /* The single letter argument e.g. -a */ |
||||
|
char *sarg; /* The string argument e.g. --arg */ |
||||
|
int cmdla_argt; /* Datatype the arg take e.g. CMDLA_TYPE_INT */ |
||||
|
cmdlap_cb cb; /* pointer to the callback funtion */ |
||||
|
int cmdla_type; /* requires parameter? e.g. CMDLA_REQ_ARG */ |
||||
|
void *var; /* this will be given to the callback */ |
||||
|
const char *info; /* a short description for the help */ |
||||
|
}; |
||||
|
|
||||
|
/* |
||||
|
* CoMmanDLine Argument Switch CallBack Type. |
||||
|
* This holds the definition of an argument that is a switch. |
||||
|
*/ |
||||
|
struct cmdlas_cbt { |
||||
|
char carg; /* The single letter argument e.g. -a */ |
||||
|
char *sarg; /* The string argument e.g. --arg */ |
||||
|
cmdlas_cb cb; /* pointer to the callback funtion */ |
||||
|
void *var; /* this will be given to the callback */ |
||||
|
const char *info; /* a short description for the help */ |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* The defaul usage method....this was previously static within |
||||
|
* cmdla but i realised that it is useful to make it callable |
||||
|
* within the calling code to do special usage in special cases |
||||
|
* and call this if no special case occured. |
||||
|
*/ |
||||
|
int default_usage_cb (void *); |
||||
|
|
||||
|
/* |
||||
|
* a default callback for struct cmdlap_cbt. It simply parses its first |
||||
|
* argument into its last according to the type specified by its sec. arg. |
||||
|
*/ |
||||
|
int get_cmdlap_cb (const char *, const int, void *); |
||||
|
|
||||
|
/* |
||||
|
* this does all the work. |
||||
|
* Arguments are: (argc, argv, a program description, a copyright string, |
||||
|
* additional text for the usage information, |
||||
|
* a list of arguments with parameter, a list of switches). |
||||
|
*/ |
||||
|
int process_cmd_line ( |
||||
|
int, char *[], const char*, const char*, const char*, |
||||
|
const struct cmdlap_cbt *, const struct cmdlas_cbt *); |
||||
|
|
||||
|
int switch_cb (void *); |
||||
|
int inc_cb (void *); |
||||
|
|
||||
|
#endif /* CMDLA_H */ |
||||
@ -0,0 +1,26 @@ |
|||||
|
/* |
||||
|
* dir_common.h: definitions and prototypes common for all plattforms with |
||||
|
* dir.c |
||||
|
* |
||||
|
* Copyright (C) 2006 Georg Steffers |
||||
|
* |
||||
|
* Author: Georg Steffers [GST] <georg.steffers@aschendorff.de> |
||||
|
* Developer: |
||||
|
* |
||||
|
* Changes (for this file only): |
||||
|
* (2006-06-12) [GST] Started this changelog...well the program is |
||||
|
* ready since some weeks right now. |
||||
|
*/ |
||||
|
#ifndef DIR_COMMON_H |
||||
|
#define DIR_COMMON_H |
||||
|
|
||||
|
/* return values for get_dir_next */ |
||||
|
#define GET_DIRENT_OK 0x00 |
||||
|
#define NO_FILES_LEFT 0x01 |
||||
|
#define GET_DIRENT_ERR 0x02 |
||||
|
|
||||
|
/* flags for symlink following */ |
||||
|
#define FOLLOW_SYM 0x00 |
||||
|
#define DONT_FOLLOW_SYM 0x01 |
||||
|
|
||||
|
#endif /* DIR_COMMON_H */ |
||||
@ -0,0 +1,106 @@ |
|||||
|
#ifndef SCOT_EVENT_H |
||||
|
#define SCOT_EVENT_H |
||||
|
|
||||
|
#include <stddef.h> |
||||
|
|
||||
|
#include <scot/scot_int.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
#define SCOT_EVENT_NO uint16_t |
||||
|
|
||||
|
/* |
||||
|
* basis event struktur. Ein Typ und die wirkliche größe. |
||||
|
*/ |
||||
|
struct scot_event |
||||
|
{ |
||||
|
SCOT_EVENT_NO event; |
||||
|
uint32_t size; /* is used with serialization. If an event |
||||
|
was serialized and send over a datalink, |
||||
|
it is possible that not all data is read |
||||
|
at once. So i can first read |
||||
|
sizeof (struct scot_event) and then i |
||||
|
know exactly how much has to be read for |
||||
|
the whole event. */ |
||||
|
uint32_t ed_size; /* This reflects the size of the extra_data |
||||
|
buffer...when serializing is done it is |
||||
|
neccessary to know where extra_data ends, |
||||
|
and as it could be any arbitrary data this |
||||
|
could not be guessed by the code. */ |
||||
|
void * extra_data; /* maybe this should hold the object that |
||||
|
an callback function to this event belongs |
||||
|
to. */ |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
struct scot_event * scot_event_new (struct scot_event *, |
||||
|
SCOT_EVENT_NO , void *, SIZE_T); |
||||
|
SIZE_T scot_event_serialize (struct scot_event *, char **); |
||||
|
struct scot_event * scot_event_deserialize (struct scot_event *, const char *); |
||||
|
void scot_event_free (struct scot_event *); |
||||
|
|
||||
|
/* |
||||
|
* event definitionen für stream pool events |
||||
|
* Die stream pool event gruppe hat nur eine erweiterte event struktur, |
||||
|
* es ist aber auch denkbar das eine event gruppe mehrere solche strukturen |
||||
|
* einschließt. (Alle events die ein stream pool erzeugt sind read |
||||
|
* write oder exception auf einem stream und fuer alle diese events |
||||
|
* reicht es den stream handle im event mitzugeben). |
||||
|
*/ |
||||
|
struct scot_stream_pool_event |
||||
|
{ |
||||
|
struct scot_event event; |
||||
|
struct scot_stream * st; |
||||
|
}; |
||||
|
|
||||
|
struct scot_stream_pool_event * scot_stream_pool_event_new ( |
||||
|
struct scot_stream_pool_event *, |
||||
|
SCOT_EVENT_NO, void *, SIZE_T, struct scot_stream * ); |
||||
|
|
||||
|
/* |
||||
|
* event definitionen für filesystem watcher events |
||||
|
*/ |
||||
|
struct scot_fs_watcher_event |
||||
|
{ |
||||
|
struct scot_event event; |
||||
|
char * path; |
||||
|
char * name; |
||||
|
char * oldname; /* used by rename events */ |
||||
|
}; |
||||
|
|
||||
|
struct scot_fs_watcher_event * scot_fs_watcher_event_new ( |
||||
|
struct scot_fs_watcher_event *, |
||||
|
SCOT_EVENT_NO, void *, SIZE_T, |
||||
|
const char *, const char *, const char *); |
||||
|
|
||||
|
#define GEN_SCOT_EVENT_NO (group, mask, no) ((group<<24)&(mask<<18)&no) |
||||
|
#define SCOT_EVENT_GEN_MASK(exp) 1<<(exp) |
||||
|
|
||||
|
#define SCOT_EVENT_CHK_GROUP(e, g) (((e)&((SCOT_EVENT_NO)(g)<<8)) == ((g)<<8)) |
||||
|
|
||||
|
/* EG := EVENT_GROUP */ |
||||
|
#define SCOT_EG_INTERNAL ((SCOT_EVENT_NO)0) |
||||
|
#define SCOT_EG_STREAM_POOL ((SCOT_EVENT_NO)1) |
||||
|
#define SCOT_EG_FS_WATCHER ((SCOT_EVENT_NO)2) |
||||
|
|
||||
|
#define SCOT_EVENT_STREAM_POOL_READ \ |
||||
|
((SCOT_EVENT_NO)(SCOT_EG_STREAM_POOL << 8) | 0) |
||||
|
#define SCOT_EVENT_STREAM_POOL_WRITE \ |
||||
|
((SCOT_EVENT_NO)(SCOT_EG_STREAM_POOL << 8) | 1) |
||||
|
#define SCOT_EVENT_STREAM_POOL_EXCEP \ |
||||
|
((SCOT_EVENT_NO)(SCOT_EG_STREAM_POOL << 8) | 2) |
||||
|
|
||||
|
#define SCOT_EVENT_FS_WATCHER_CREATE \ |
||||
|
((SCOT_EVENT_NO)(SCOT_EG_FS_WATCHER << 8) | 0) |
||||
|
#define SCOT_EVENT_FS_WATCHER_DELETE \ |
||||
|
((SCOT_EVENT_NO)(SCOT_EG_FS_WATCHER << 8) | 1) |
||||
|
#define SCOT_EVENT_FS_WATCHER_RENAME \ |
||||
|
((SCOT_EVENT_NO)(SCOT_EG_FS_WATCHER << 8) | 2) |
||||
|
#define SCOT_EVENT_FS_WATCHER_WRITTEN \ |
||||
|
((SCOT_EVENT_NO)(SCOT_EG_FS_WATCHER << 8) | 3) |
||||
|
#define SCOT_EVENT_FS_WATCHER_ATTRCHG \ |
||||
|
((SCOT_EVENT_NO)(SCOT_EG_FS_WATCHER << 8) | 4) |
||||
|
#define SCOT_EVENT_FS_WATCHER_SIZECHG \ |
||||
|
((SCOT_EVENT_NO)(SCOT_EG_FS_WATCHER << 8) | 5) |
||||
|
|
||||
|
|
||||
|
#endif /* SCOT_EVENT_H */ |
||||
@ -0,0 +1,53 @@ |
|||||
|
#ifndef _SCOT_EVENT_LISTENER_H |
||||
|
#define _SCOT_EVENT_LISTENER_H |
||||
|
|
||||
|
#include <limits.h> |
||||
|
|
||||
|
#include <scot/scot_int.h> |
||||
|
#include <scot/event.h> |
||||
|
#include <scot/thread.h> |
||||
|
|
||||
|
#include <scot/stack_type_proto.h> |
||||
|
|
||||
|
/* valid return codes for the callbacks */ |
||||
|
#define SCOT_EVENT_END 0x00 |
||||
|
#define SCOT_EVENT_CONT 0x01 |
||||
|
#define SCOT_EVENT_CONT_DATA_DONE 0x02 |
||||
|
|
||||
|
#define SCOT_EL_WAIT_THREAD_MAX INFINITE |
||||
|
|
||||
|
|
||||
|
typedef unsigned short (*scot_event_cb_fptr) (struct scot_event *); |
||||
|
|
||||
|
GEN_STACK_TYPE_PROTO (scot_event_cb_fptr); |
||||
|
|
||||
|
struct scot_event_listener |
||||
|
{ |
||||
|
unsigned char group; |
||||
|
|
||||
|
stack_scot_event_cb_fptr_node_t * cb_mappings[UCHAR_MAX]; |
||||
|
void * cb_extra_data[UCHAR_MAX]; |
||||
|
|
||||
|
THREAD_T thread_handle; |
||||
|
THREAD_ID_T thread_id; |
||||
|
int thread_run_flg; |
||||
|
|
||||
|
scot_thread_entry_fptr el_entry_func; |
||||
|
}; |
||||
|
typedef struct scot_event_listener scot_event_listener; |
||||
|
|
||||
|
void scot_event_listener_init (struct scot_event_listener *, |
||||
|
const unsigned char , |
||||
|
const scot_thread_entry_fptr); |
||||
|
void scot_event_listener_fini (struct scot_event_listener *); |
||||
|
void scot_event_listener_start (struct scot_event_listener *); |
||||
|
void scot_event_listener_stop (struct scot_event_listener *); |
||||
|
int scot_event_listener_is_running (struct scot_event_listener *); |
||||
|
void scot_event_listener_register_cb (struct scot_event_listener *, |
||||
|
SCOT_EVENT_NO , |
||||
|
scot_event_cb_fptr , |
||||
|
void *); |
||||
|
void scot_event_listener_call_cb (struct scot_event_listener *, |
||||
|
struct scot_event *); |
||||
|
|
||||
|
#endif /* _SCOT_EVENT_LISTENER_H */ |
||||
@ -0,0 +1,52 @@ |
|||||
|
/** |
||||
|
* \file scot/excenv_t.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief The datatypes for exception environments. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef STACK_EXCENV_T_H |
||||
|
#define STACK_EXCENV_T_H |
||||
|
|
||||
|
#include <setjmp.h> |
||||
|
|
||||
|
#include <scot/exception_t.h> |
||||
|
|
||||
|
struct excenv_t; |
||||
|
typedef struct excenv_t excenv_t; |
||||
|
|
||||
|
#ifndef USE_SCOT_STRUCT_EXCENV_T |
||||
|
struct excenv_t |
||||
|
{ |
||||
|
const char _ [sizeof (struct { |
||||
|
jmp_buf env; |
||||
|
void *e_queue; |
||||
|
})]; |
||||
|
}; |
||||
|
#else |
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief holds an exception environment. |
||||
|
*/ |
||||
|
struct excenv_t |
||||
|
{ |
||||
|
jmp_buf env; /**< jump here on error. */ |
||||
|
queue_exception_t_node_t *e_queue; /**< holds the exceptions. */ |
||||
|
}; |
||||
|
#endif |
||||
|
|
||||
|
#endif /* STACK_EXCENV_T_H */ |
||||
@ -0,0 +1,133 @@ |
|||||
|
/** |
||||
|
* \file scot/exception.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief The user interface to exception handling. |
||||
|
* |
||||
|
* This describes the macros TRY, CATCH, THROW and EXC. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef EXCEPTION_H |
||||
|
#define EXCEPTION_H |
||||
|
|
||||
|
#include <setjmp.h> |
||||
|
|
||||
|
#include "excenv_t.h" |
||||
|
#include "exception_t.h" |
||||
|
#include <scot/thread.h> |
||||
|
|
||||
|
|
||||
|
#ifdef USE_THREADS |
||||
|
# define EXC_INIT threaded_exc_init |
||||
|
#else |
||||
|
# define EXC_INIT exc_init |
||||
|
#endif /* USE_THREADS */ |
||||
|
|
||||
|
/** |
||||
|
* \pre None |
||||
|
* \return Nothing |
||||
|
* \post a current exception environment exists. |
||||
|
* |
||||
|
* \brief start exception handled code. |
||||
|
* |
||||
|
* This starts a block of exception handled code. This is done by |
||||
|
* creating a current exception environment. |
||||
|
*/ |
||||
|
#define TRY \ |
||||
|
{ \ |
||||
|
excenv_new (EXC_INIT ()); \ |
||||
|
if (setjmp (* excenv_jmp_buf (EXC_INIT ())) == 0) |
||||
|
|
||||
|
/** |
||||
|
* \param ee will hold the exception environment actually handled. |
||||
|
* \pre a current exception environment must exists. |
||||
|
* \return Nothing |
||||
|
* \post ee holds the current exception environment and it is removed |
||||
|
* from the stack of exception environments. |
||||
|
* |
||||
|
* \brief start exception handling. |
||||
|
* |
||||
|
* This starts a block of exception handling. This is done by |
||||
|
* retrieving the actual exception environment into \a ee. |
||||
|
*/ |
||||
|
#define CATCH(ee) \ |
||||
|
ee = excenv_catch (EXC_INIT ()); \ |
||||
|
} \ |
||||
|
if (excenv_has_exception(ee) == 0) \ |
||||
|
free_catched (ee); \ |
||||
|
else |
||||
|
|
||||
|
/** |
||||
|
* \param e the exception to be thrown. |
||||
|
* \pre a current exception environment must exist. |
||||
|
* \return Nothing |
||||
|
* \post \a e is put into the current exception environment. |
||||
|
* |
||||
|
* \brief Throws an exception into the actual exception environment. |
||||
|
*/ |
||||
|
#define THROW(e) \ |
||||
|
exc_throw (EXC_INIT (), (e)) |
||||
|
|
||||
|
/** |
||||
|
* \brief this is just a wrapper around exc_new(). |
||||
|
* |
||||
|
* This is just a wrapper around exc_new() that fills in automatically |
||||
|
* file and line. |
||||
|
*/ |
||||
|
#define EXC(lvl, errnum, err_msg) \ |
||||
|
exc_new (lvl, __FILE__, __LINE__, errnum, err_msg) |
||||
|
|
||||
|
/** |
||||
|
* \brief a wrapper for exc_in_this_try() |
||||
|
*/ |
||||
|
#define EXC_IN_THIS_TRY(e) \ |
||||
|
exc_in_this_try (e) |
||||
|
|
||||
|
void * exc_init (); |
||||
|
void * threaded_exc_init (); |
||||
|
|
||||
|
void excenv_new (void *); |
||||
|
jmp_buf * excenv_jmp_buf (void *); |
||||
|
void exc_throw (void *, const exception_t *); |
||||
|
excenv_t * excenv_catch (void *); |
||||
|
int excenv_has_exception (const excenv_t *); |
||||
|
|
||||
|
exception_t * exc_new ( |
||||
|
const enum exclvl_t, |
||||
|
const char *, |
||||
|
const int, |
||||
|
const int, |
||||
|
const char *); |
||||
|
|
||||
|
exception_t * retrive_exception (const excenv_t *); |
||||
|
|
||||
|
void free_catched (excenv_t *); |
||||
|
void free_exception (exception_t *); |
||||
|
void thread_exc_end (THREAD_T); |
||||
|
void exc_end (void); |
||||
|
|
||||
|
void print_exception (exception_t *); |
||||
|
void print_all_exceptions (excenv_t *); |
||||
|
void forward_all_exceptions (excenv_t *); |
||||
|
|
||||
|
int exc_in_this_try (exception_t *); |
||||
|
enum exclvl_t exc_lvl_get (exception_t *); |
||||
|
char * exc_file_get (exception_t *); |
||||
|
int exc_line_get (exception_t *); |
||||
|
int exc_errnum_get (exception_t *); |
||||
|
char * exc_err_msg_get (exception_t *); |
||||
|
#endif /* EXCEPTION_H */ |
||||
@ -0,0 +1,68 @@ |
|||||
|
/** |
||||
|
* \file scot/exception_t.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief The datatypes for exceptions. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef STACK_EXCEPTION_T_H |
||||
|
#define STACK_EXCEPTION_T_H |
||||
|
|
||||
|
/** |
||||
|
* \brief give the two states a speaking name. |
||||
|
* |
||||
|
* There are two exceptions possible EXC_ERRORS, that immediatly abort the |
||||
|
* current operation and EXC_WARNINGS, that will just be mentioned within |
||||
|
* the exception stack. |
||||
|
*/ |
||||
|
enum exclvl_t {EXC_WARNING, EXC_ERROR}; |
||||
|
|
||||
|
struct exception_t; |
||||
|
typedef struct exception_t exception_t; |
||||
|
|
||||
|
#ifndef USE_SCOT_STRUCT_EXCEPTION_T |
||||
|
struct exception_t |
||||
|
{ |
||||
|
const char _ [sizeof (struct { |
||||
|
int was_catched; |
||||
|
const enum exclvl_t lvl; |
||||
|
const char *file; |
||||
|
const int line; |
||||
|
const int errnum; |
||||
|
const char *err_msg; |
||||
|
})]; |
||||
|
}; |
||||
|
#else |
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief holds an exception. |
||||
|
*/ |
||||
|
struct exception_t |
||||
|
{ |
||||
|
int was_catched; /**< how often was it catched */ |
||||
|
const enum exclvl_t lvl; /**< EXC_ERROR or EXC_WARNING */ |
||||
|
const char *file; /**< file where it was created */ |
||||
|
const int line; /**< line of that file */ |
||||
|
const int errnum; /**< number of the error */ |
||||
|
const char *err_msg; /**< message of the error */ |
||||
|
}; |
||||
|
|
||||
|
#include <scot/queue_type_proto.h> |
||||
|
GEN_QUEUE_TYPE_PROTO (exception_t); |
||||
|
#endif |
||||
|
|
||||
|
#endif /* STACK_EXCEPTION_T_H */ |
||||
@ -0,0 +1,47 @@ |
|||||
|
#ifndef SCOT_FS_WATCHER_H |
||||
|
#define SCOT_FS_WATCHER_H |
||||
|
|
||||
|
#include <scot/event_listener.h> |
||||
|
#include <scot/thread.h> |
||||
|
#include <scot/stream.h> |
||||
|
|
||||
|
#include <scot/list_type_proto.h> |
||||
|
|
||||
|
struct scot_fsw_info |
||||
|
{ |
||||
|
int watch_d; |
||||
|
char * path; |
||||
|
uint32_t mask; |
||||
|
uint32_t got_events; /* also a mask, that shows, which events already |
||||
|
occured (will be 0 at init and after a callback was |
||||
|
called.) */ |
||||
|
char * old_name; /* This is used within rename events. With inotify |
||||
|
a rename is build up from 2 inotify_events. |
||||
|
IN_MOVE_FROM and IN_MOVE_TO. The move from |
||||
|
event holds the old name. This old name is saved |
||||
|
here if an IN_MOVE_FORM occured. */ |
||||
|
}; |
||||
|
typedef struct scot_fsw_info scot_fsw_info; |
||||
|
GEN_LIST_TYPE_PROTO (scot_fsw_info); |
||||
|
|
||||
|
struct scot_fs_watcher |
||||
|
{ |
||||
|
struct scot_event_listener el; |
||||
|
fd_set rfds; |
||||
|
struct scot_stream notify_d; |
||||
|
|
||||
|
list_scot_fsw_info_node_t * w_list; |
||||
|
THREAD_MUTEX_T mutex; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
struct scot_fs_watcher * scot_fs_watcher_new (void); |
||||
|
void scot_fs_watcher_free (struct scot_fs_watcher *); |
||||
|
|
||||
|
void scot_fs_watcher_add (struct scot_fs_watcher *, const char *, uint32_t); |
||||
|
void scot_fs_watcher_remove (struct scot_fs_watcher *, const char *, uint32_t); |
||||
|
|
||||
|
int scot_fs_watcher_get_mask (struct scot_fs_watcher *, int); |
||||
|
void scot_fs_watcher_main_loop (struct scot_fs_watcher *); |
||||
|
|
||||
|
#endif /* SCOT_FS_WATCHER_H */ |
||||
@ -0,0 +1,31 @@ |
|||||
|
#ifndef INOTIFY_H |
||||
|
#define INOTIFY_H |
||||
|
|
||||
|
#include <sys/syscall.h> |
||||
|
#include <asm/unistd.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <linux/inotify.h> |
||||
|
|
||||
|
#define IN_NEXT_EVENT(ev) \ |
||||
|
(struct inotify_event *) \ |
||||
|
((char *)(ev) + sizeof (struct inotify_event) + (ev)->len) |
||||
|
|
||||
|
#define IN_NO_EVENT(ev) ((ev)->mask|IN_ALL_EVENTS) == IN_ALL_EVENTS |
||||
|
|
||||
|
|
||||
|
static inline int inotify_init (void) |
||||
|
{ |
||||
|
return syscall (__NR_inotify_init); |
||||
|
} |
||||
|
|
||||
|
static inline int inotify_add_watch (int fd, const char *name, __u32 mask) |
||||
|
{ |
||||
|
return syscall (__NR_inotify_add_watch, fd, name, mask); |
||||
|
} |
||||
|
|
||||
|
static inline int inotify_rm_watch (int fd, __u32 wd) |
||||
|
{ |
||||
|
return syscall (__NR_inotify_rm_watch, fd, wd); |
||||
|
} |
||||
|
|
||||
|
#endif /* INOTIFY_H */ |
||||
@ -0,0 +1,64 @@ |
|||||
|
/** |
||||
|
* \file scot/list.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro which produce all prototypes and implementations |
||||
|
* for handling linked lists from Templates. |
||||
|
* |
||||
|
* This is the toplevel template file for typesafe lists. It is quite |
||||
|
* simple. It just defines one MACRO which in turn calls two other macros |
||||
|
* to generate all that is needed for listhandling of a list to a given type. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef LIST_H |
||||
|
#define LIST_H |
||||
|
|
||||
|
#include <scot/list_proto.h> |
||||
|
#include <scot/list_impl.h> |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The complete framework of functions, types, globals |
||||
|
* prototypes and definitions to handle typesave |
||||
|
* lists for the given datatype are generated within the |
||||
|
* calling build file. |
||||
|
* |
||||
|
* \brief create complete framework to handle typesafe lists. |
||||
|
* |
||||
|
* This macro first colls GEN_LIST_PROTO() to create all prototypes |
||||
|
* neccesary for handling lists of the given \a type. And then it calls |
||||
|
* GEN_LIST_IMPL() to also create the neccesary definitions and |
||||
|
* implementations.\ |
||||
|
* Normally this macro is only called if one only wants to have lists |
||||
|
* of the given type in a single c source file and nowhere else. Normally |
||||
|
* this is then used in conjunction with a previous define of GEN_LOCAL, |
||||
|
* that tells GEN_LIST() and the subsequent macros to generate the functions |
||||
|
* as static.\n |
||||
|
* If one wants to used lists of the given type in several places of the |
||||
|
* project one would normally call GEN_LIST_PROTO() in a h file and |
||||
|
* GEN_LIST_IMPL() in the corresponding c file (without GEN_LOCAL), |
||||
|
*/ |
||||
|
#define GEN_LIST(type) \ |
||||
|
GEN_LIST_PROTO (type) \ |
||||
|
GEN_LIST_IMPL (type) |
||||
|
|
||||
|
#endif /* LIST_H */ |
||||
@ -0,0 +1,214 @@ |
|||||
|
/** |
||||
|
* \file scot/list_func_proto.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro that produce function prototypes for handling |
||||
|
* linked lists. |
||||
|
* |
||||
|
* The macros here create all function prototypes to |
||||
|
* the implementations created by the macros in |
||||
|
* \link scot/list_impl.h scot/list_impl.h\endlink. |
||||
|
* These macros are normally not called directly within your code but |
||||
|
* through \link scot/list_proto.h::GEN_LIST_PROTO GEN_LIST_PROTO\endlink. |
||||
|
* This is because to use the interface declaration |
||||
|
* provided here one will also need the typedefs and datatype prototypes. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef LIST_FUNC_PROTO_H |
||||
|
#define LIST_FUNC_PROTO_H |
||||
|
|
||||
|
#ifdef GEN_LOCAL |
||||
|
# define STATIC static |
||||
|
#else |
||||
|
# define STATIC |
||||
|
#endif |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The function prototypes for manage lists of the given |
||||
|
* datatype are created. |
||||
|
* |
||||
|
* \brief Function prototypes for management. |
||||
|
* |
||||
|
* This creates the prototypes to the functions that are created by |
||||
|
* \link scot/list_man.h::GEN_LIST_MANAGEMENT GEN_LIST_MANAGEMENT\endlink |
||||
|
* in \link scot/list_man.h scot/list_man.h\endlink. |
||||
|
* |
||||
|
* Normally this is not called directly, but by |
||||
|
* \link scot/list_proto.h::GEN_LIST_PROTO GEN_LIST_PROTO()\endlink |
||||
|
* because this defined just a subset of all function prototypes neccesarry |
||||
|
* to handle typesafe lists. |
||||
|
*/ |
||||
|
#define GEN_LIST_MAN_PROTO(type) \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
list_ ## type ## _set_cmp ( \ |
||||
|
list_ ## type ## _cmp_fptr); \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
list_ ## type ## _set_elem_free ( \ |
||||
|
list_ ## type ## _elem_free_fptr); \ |
||||
|
STATIC \ |
||||
|
long \ |
||||
|
list_ ## type ## _elem_free_is_set (void); \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _new ( \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
list_ ## type ## _free ( \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
int \ |
||||
|
list_ ## type ## _count ( \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
int \ |
||||
|
list_ ## type ## _bol ( \ |
||||
|
list_ ## type ## _node_t *, \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
int \ |
||||
|
list_ ## type ## _eol ( \ |
||||
|
list_ ## type ## _node_t *anchor, \ |
||||
|
list_ ## type ## _node_t *node); |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The function prototypes to navigate lists of the given |
||||
|
* datatype are created. |
||||
|
* |
||||
|
* \brief Function prototypes for navigation. |
||||
|
* |
||||
|
* This creates the prototypes to the functions that are created by |
||||
|
* \link scot/list_nav.h::GEN_LIST_NAVIGATION GEN_LIST_NAVIGATION\endlink |
||||
|
* in \link scot/list_nav.h scot/list_nav.h\endlink. |
||||
|
* |
||||
|
* Normally this is not called directly, but by |
||||
|
* \link scot/list_proto.h::GEN_LIST_PROTO GEN_LIST_PROTO()\endlink |
||||
|
* because this defined just a subset of all function prototypes neccesarry |
||||
|
* to handle typesafe lists. |
||||
|
*/ |
||||
|
#define GEN_LIST_NAV_PROTO(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _front ( \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _last ( \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _next ( \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _prev ( \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _find ( \ |
||||
|
list_ ## type ## _node_t *, \ |
||||
|
const type *); \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _find_anchor ( \ |
||||
|
list_ ## type ## _node_t *); |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The function prototypes to modify lists of the given |
||||
|
* datatype are created. |
||||
|
* |
||||
|
* \brief Function prototypes for modification. |
||||
|
* |
||||
|
* This creates the prototypes to the functions that are created by |
||||
|
* \link scot/list_mod.h::GEN_LIST_MODIFY GEN_LIST_MODIFY\endlink |
||||
|
* in \link scot/list_mod.h scot/list_mod.h\endlink. |
||||
|
* |
||||
|
* Normally this is not called directly, but by |
||||
|
* \link scot/list_proto.h::GEN_LIST_PROTO GEN_LIST_PROTO()\endlink |
||||
|
* because this defined just a subset of all function prototypes neccesarry |
||||
|
* to handle typesafe lists. |
||||
|
*/ |
||||
|
#define GEN_LIST_MOD_PROTO(type) \ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
list_ ## type ## _retrive ( \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
list_ ## type ## _set ( \ |
||||
|
list_ ## type ## _node_t *, \ |
||||
|
const type *); \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _insert ( \ |
||||
|
list_ ## type ## _node_t *, \ |
||||
|
const type *); \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _delete ( \ |
||||
|
list_ ## type ## _node_t *); \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _concat ( \ |
||||
|
list_ ## type ## _node_t *, \ |
||||
|
list_ ## type ## _node_t *); |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post All function prototypes for a lists of the given |
||||
|
* datatype are created. |
||||
|
* |
||||
|
* \brief Calls GEN_LIST_MAN_PROTO, GEN_LIST_NAV_PROTO and GEN_LIST_MOD_PROTO. |
||||
|
* |
||||
|
* This creates all the prototypes to the functions that are created by |
||||
|
* \link scot/list_impl.h::GEN_LIST_IMPL GEN_LIST_IMPL\endlink in |
||||
|
* \link scot/list_impl.h scot/list_impl.h\endlink. |
||||
|
* This provides one with the complete interface to the list of the given |
||||
|
* datatype. |
||||
|
*/ |
||||
|
#define GEN_LIST_FUNC_PROTO(type) \ |
||||
|
GEN_LIST_MAN_PROTO (type); \ |
||||
|
GEN_LIST_NAV_PROTO (type); \ |
||||
|
GEN_LIST_MOD_PROTO (type); |
||||
|
|
||||
|
#endif /* LIST_FUNC_PROTO_H */ |
||||
@ -0,0 +1,252 @@ |
|||||
|
/** |
||||
|
* \file scot/list_impl.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro which creates functions for typesafe lists by templates. |
||||
|
* |
||||
|
* This combines the macro definitions in \link scot/list_man.h scot/list_man.h |
||||
|
* \endlink, \link scot/list_mod.h scot/list_mod.h \endlink and \link |
||||
|
* scot/list_nav.h scot/list_nav.h\endlink into one macro that is |
||||
|
* normally called within a c file that wants to use lists, as it provides |
||||
|
* you with all functions neccesary for list handling.\n |
||||
|
* Additionally the whole errorhandling code for lists is here. For that |
||||
|
* there are some function prototypes of functions implemented in |
||||
|
* \link list.c\endlink here. These functions do error output or will |
||||
|
* throw exceptions. Which function is called depends on if |
||||
|
* \link exception.c::USE_NO_EXCEPTIONS USE_NO_EXCEPTIONS\endlink is set at |
||||
|
* include time of this file, or not. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef LIST_IMPL_H |
||||
|
#define LIST_IMPL_H |
||||
|
|
||||
|
|
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param type the datatype that this queue code should handle. |
||||
|
* \param a a variable holding a pointer to queue_[type]_node_t. |
||||
|
* |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* a must be a valid pointer to a queue_[type]_node_t. |
||||
|
* \returns \a a cast to a pointer of list_[type]_node_t. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Cast a pointer to list_[type]_node_t. |
||||
|
* |
||||
|
* FIXME: I should check better the validity of \a a. |
||||
|
*/ |
||||
|
#define LIST(type, a) (list_ ## type ## _node_t *) (a) |
||||
|
|
||||
|
void list_error_print (const char *, int, int); |
||||
|
void list_warning_print (const char *, int, int); |
||||
|
void list_error_throw (const char *, int, int); |
||||
|
void list_warning_throw (const char *, int, int); |
||||
|
void * list_malloc_print (SIZE_T, const char *, int); |
||||
|
void list_check_null_print (const void *, const char *, int); |
||||
|
void * list_malloc_throw (SIZE_T, const char *, int); |
||||
|
void list_check_null_throw (const void *, const char *, int); |
||||
|
|
||||
|
#ifdef USE_NO_EXCEPTION |
||||
|
# define LIST_ERROR(file, line, id) \ |
||||
|
list_error_print ((file), (line), (id)) |
||||
|
# define LIST_WARNING(file, line, id) \ |
||||
|
list_warning_print ((file), (line), (id)) |
||||
|
# define LIST_MALLOC(size, file, line) \ |
||||
|
list_malloc_print ((size), (file), (line)) |
||||
|
# define LIST_CHECK_NULL(val, file, line) \ |
||||
|
list_check_null_print ((void *) (val), (file), (line)) |
||||
|
# define LIST_EXC_START |
||||
|
# define LIST_EXC_END(file, line, id) |
||||
|
#else |
||||
|
/** |
||||
|
* \internal |
||||
|
* \param file filename of the file where the error occured. |
||||
|
* \param line line in the file where the error occured. |
||||
|
* \param id list error id. |
||||
|
* |
||||
|
* \brief print or thow an error |
||||
|
*/ |
||||
|
# define LIST_ERROR(file, line, id) \ |
||||
|
list_error_throw ((file), (line), (id)) |
||||
|
/** |
||||
|
* \internal |
||||
|
* \param file filename of the file where the error occured. |
||||
|
* \param line line in the file where the error occured. |
||||
|
* \param id list error id. |
||||
|
* |
||||
|
* \brief print or throw a warning |
||||
|
*/ |
||||
|
# define LIST_WARNING(file, line, id) \ |
||||
|
list_warning_throw ((file), (line), (id)) |
||||
|
/** |
||||
|
* \internal |
||||
|
* \param size the amount of memory that should be reserved. |
||||
|
* \param file filename of the file where this is called. |
||||
|
* \param line line in the file where this is called. |
||||
|
* |
||||
|
* \brief list malloc wrapper |
||||
|
* |
||||
|
* A malloc wrapper which either print an error or throw |
||||
|
* an exception. |
||||
|
*/ |
||||
|
# define LIST_MALLOC(size, file, line) \ |
||||
|
list_malloc_throw ((size), (file), (line)) |
||||
|
/** |
||||
|
* \internal |
||||
|
* \param val variable that should be check for NULL. |
||||
|
* \param file filename of the file where this is called. |
||||
|
* \param line line in the file where this is called. |
||||
|
* |
||||
|
* \brief this checks if val is null |
||||
|
*/ |
||||
|
# define LIST_CHECK_NULL(val, file, line) \ |
||||
|
list_check_null_throw ((void *) (val), (file), (line)) |
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief start exception environment in generated list function. |
||||
|
*/ |
||||
|
# define LIST_EXC_START \ |
||||
|
{ \ |
||||
|
excenv_t *ee; \ |
||||
|
TRY { |
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief end the exception environment of the generated list function. |
||||
|
* |
||||
|
* This ends the exception environment in the generated list |
||||
|
* function, that was started with LIST_EXC_START. |
||||
|
* Any exception that had occured will be forwarded in the upper |
||||
|
* exception environment and if exceptions had occured a new one |
||||
|
* will be thrown to the exception environment indicating that the |
||||
|
* function fails. |
||||
|
*/ |
||||
|
# define LIST_EXC_END(file, line, id) \ |
||||
|
} \ |
||||
|
CATCH (ee) \ |
||||
|
{ \ |
||||
|
forward_all_exceptions (ee); \ |
||||
|
list_error_throw ((file), (line), (id)); \ |
||||
|
} \ |
||||
|
} |
||||
|
#endif /* USE_NO_EXCEPTION */ |
||||
|
|
||||
|
extern const char *list_err_msg[]; |
||||
|
extern const char *list_wrn_msg[]; |
||||
|
|
||||
|
struct list_node_t |
||||
|
{ |
||||
|
const char _ [sizeof (struct { |
||||
|
const void *e; |
||||
|
const void *prev; |
||||
|
const void *next; |
||||
|
})]; |
||||
|
}; |
||||
|
|
||||
|
#ifdef GEN_LOCAL |
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief make functions static or not dependig on if GEN_LOCAL was |
||||
|
* defined or not. |
||||
|
*/ |
||||
|
# define STATIC static |
||||
|
#else |
||||
|
# define STATIC |
||||
|
#endif |
||||
|
|
||||
|
#include "list_man.h" |
||||
|
#include "list_nav.h" |
||||
|
#include "list_mod.h" |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The functions, struct and globals to handle typesave |
||||
|
* lists for the given datatype are generated within the |
||||
|
* calling build file. |
||||
|
* FIXME: This seems not threadsafe to me, as the globals |
||||
|
* are used within all threads. Actually one could work |
||||
|
* around this because normally it is enough to set the |
||||
|
* comparison functions once and dont touch them anymore |
||||
|
* but it might be neccesary to compare elements within |
||||
|
* the list differently in different threads. |
||||
|
* |
||||
|
* \brief this creates all functions, structs and globals needed for a |
||||
|
* typesafe list of a given \a type. |
||||
|
* |
||||
|
* In detail the following is created by this macro:\n |
||||
|
* \li <b>struct list_[type]_node_t</b>: This is the structure a list |
||||
|
* is constructed of. A representation of a double linked list node with |
||||
|
* a pointer to the element it contains, a pointer to the next and a pointer |
||||
|
* to the previous element in the list. This list implementation uses a kind |
||||
|
* of a ringlist, that is the next pointer of the last node in the list |
||||
|
* and the prev pointer in the first element of the list points to the anchor. |
||||
|
* Thus in an empty list prev and next of the anchor both points to the |
||||
|
* anchor. |
||||
|
* \li <b>int list_[type]_default_cmp ()</b>: This is the default |
||||
|
* comparison function for lists. It simply compares the adresses of two |
||||
|
* elements. At list initialization list_[type]_compare() is set to this. |
||||
|
* \li <b>list_[type]_cmp_fptr list_[type]_compare</b>: This pointer |
||||
|
* to a function that compares list elements is used within the generated |
||||
|
* list functions. |
||||
|
* \li <b>list_[type]_elem_free_fptr list_[type]_elem_free</b>: This pointer |
||||
|
* , if set to non NULL, is used in list_[type]_delete() to free an |
||||
|
* element within a node before deleting the node. At initial time of |
||||
|
* the list code this is set to NULL, thus elements are not freed at all. |
||||
|
* (This is ok when stack variables are used, else one should at least |
||||
|
* set list_[type]_elem_free to free().) |
||||
|
* \li all functions defined in \link scot/list_man.h list_man.h\endlink, |
||||
|
* \link scot/list_mod.h list_mod.h\endlink and |
||||
|
* \link scot/list_nav.h list_nav.h\endlink. |
||||
|
*/ |
||||
|
#define GEN_LIST_IMPL(type) \ |
||||
|
struct list_ ## type ## _node_t \ |
||||
|
{ \ |
||||
|
const type *e; \ |
||||
|
struct list_ ## type ## _node_t *prev; \ |
||||
|
struct list_ ## type ## _node_t *next; \ |
||||
|
}; \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
int list_ ## type ## _default_cmp ( \ |
||||
|
const type * a, \ |
||||
|
const type * b) \ |
||||
|
{ \ |
||||
|
return (a==b)?0:(a<b)?-1:1; \ |
||||
|
} \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _cmp_fptr \ |
||||
|
list_ ## type ## _compare = list_ ## type ## _default_cmp; \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _elem_free_fptr \ |
||||
|
list_ ## type ## _elem_free = NULL; \ |
||||
|
\ |
||||
|
GEN_LIST_MANAGEMENT (type); \ |
||||
|
GEN_LIST_NAVIGATION (type); \ |
||||
|
GEN_LIST_MODIFY (type); |
||||
|
|
||||
|
#endif /* LIST_IMPL_H */ |
||||
@ -0,0 +1,382 @@ |
|||||
|
/** |
||||
|
* \file scot/list_man.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Templates of functions to manage typesafe lists. |
||||
|
* |
||||
|
* Here are macro definitions that create functions to manage typesafe |
||||
|
* lists. That is create new list, free list, check nodes a.s.f |
||||
|
* |
||||
|
* Normally the macros defined here will be never called directly but only |
||||
|
* via MACROS that group them in a sensefull way in scot/list_impl.h.\n |
||||
|
* \anchor onlyfunc_man |
||||
|
* \attention |
||||
|
* All documentation here does document the functions that are created by |
||||
|
* the macros, as the macros themself are pretty easy and all used the same. |
||||
|
* They are called with a type, that MUST be one word (use typedef if needed) |
||||
|
* and generates the function defined with their value. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef LIST_MAN_H |
||||
|
#define LIST_MAN_H |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
#include <scot/list_impl.h> |
||||
|
#include <scot/memory.h> /* because we use functions from there */ |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param node a list_[type]_node_t* that should be checked for |
||||
|
* beeing an anchor. |
||||
|
* \param line the line where this MACRO is called. |
||||
|
* \pre a variable of type list_[type]_node_t* must exist. |
||||
|
* \return the code fragment |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief check for anchor. |
||||
|
* |
||||
|
* This checks if the given \a node is an anchor. If not it calls |
||||
|
* LIST_ERROR, which either raises an exception if exceptions are user |
||||
|
* or otherwise prints out an error message to stderr and aborts the |
||||
|
* program. |
||||
|
*/ |
||||
|
#define MAN_NODE_NO_ANCHOR_ERROR(node, line) \ |
||||
|
if ((node->e) != NULL) \ |
||||
|
LIST_ERROR ("list_man.h", (line), NODE_NO_ANCHOR_ERR); |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \pre None |
||||
|
* \return NULL on error, but only if no exceptions are used. |
||||
|
* If exceptions are used an exception is thrown on error. |
||||
|
* On success a pointer to the newly created list_anchor |
||||
|
* will be returned. |
||||
|
* \retval NULL if an error occurs and no exceptions are used. |
||||
|
* \retval !=NULL the pointer to the newly created list anchor. |
||||
|
* \post enough memory on the heap. |
||||
|
* |
||||
|
* \brief template for list constructor. |
||||
|
* |
||||
|
* The function creates a new list anchor on the heap and returns it. |
||||
|
* This can be used with following list_[type]_*() functions. |
||||
|
* The memory reserved for this anchor must be freed by the context |
||||
|
* that uses this function if it did not need the list anymore.\n\n |
||||
|
*/ |
||||
|
#define GEN_LIST_NEW(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _new (list_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
anchor = (list_ ## type ## _node_t *) \ |
||||
|
LIST_MALLOC (sizeof (list_ ## type ## _node_t), \ |
||||
|
"list_man.h", 93); \ |
||||
|
\ |
||||
|
anchor->e = NULL; \ |
||||
|
anchor->prev = anchor; \ |
||||
|
anchor->next = anchor; \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_man.h", 99, LIST_NEW_ERR); \ |
||||
|
\ |
||||
|
return anchor; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param anchor A pointer to the list anchor. |
||||
|
* \pre anchor must point to a valid list anchor previously |
||||
|
* assigned by list_[type]_new(). |
||||
|
* \return Nothing |
||||
|
* \post The list is completely removed from the heap. |
||||
|
* |
||||
|
* \brief template for list destructor. |
||||
|
* |
||||
|
* The function frees a list given by its anchor. It uses list_[type]_delete() |
||||
|
* to delete every node one by one and finally it calls free on the anchor. |
||||
|
* list_[type]_delete does by default only delete the node and not the |
||||
|
* stored element. Read here to learn more. |
||||
|
*/ |
||||
|
#define GEN_LIST_FREE(type) \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
list_ ## type ## _free (list_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *next; \ |
||||
|
\ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
LIST_CHECK_NULL (anchor, "list_man.h", 48); \ |
||||
|
MAN_NODE_NO_ANCHOR_ERROR (anchor, 49); \ |
||||
|
\ |
||||
|
next = list_ ## type ## _next (anchor); \ |
||||
|
while (anchor != next) \ |
||||
|
next = list_ ## type ## _delete (next); \ |
||||
|
\ |
||||
|
SCOT_MEM_FREE (anchor); \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_man.h", 58, LIST_FREE_ERR); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param anchor A pointer to the list anchor. |
||||
|
* \param e A pointer to a variable of the \a type, the |
||||
|
* list was created for. |
||||
|
* \pre The \a anchor has to be not NULL and a valid |
||||
|
* anchor.\a e must not be NULL. |
||||
|
* \return The node that contains \a e. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Find the node in the list that contains \a e. |
||||
|
*/ |
||||
|
#define GEN_LIST_COUNT(type) \ |
||||
|
STATIC \ |
||||
|
int \ |
||||
|
list_ ## type ## _count (list_ ## type ## _node_t * anchor) \ |
||||
|
{ \ |
||||
|
int ret = 0; \ |
||||
|
\ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *node; \ |
||||
|
\ |
||||
|
LIST_CHECK_NULL (anchor, "list_nav.h", 170); \ |
||||
|
NAV_NODE_NO_ANCHOR_ERROR (anchor, 171); \ |
||||
|
\ |
||||
|
node = anchor; \ |
||||
|
while (! list_ ## type ## _eol (anchor, node)) \ |
||||
|
{ \ |
||||
|
node = node->next; \ |
||||
|
\ |
||||
|
if (node->e != NULL) \ |
||||
|
ret ++; \ |
||||
|
} \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_man.h", 182, LIST_COUNT_ERR); \ |
||||
|
\ |
||||
|
return ret; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param anchor A pointer to the list anchor. |
||||
|
* \param node A pointer to a node in the list. |
||||
|
* \pre The \a anchor has to be not NULL and a valid |
||||
|
* anchor, the node has to be not NULL too. |
||||
|
* \return A boolean indicating if the first non-anchor |
||||
|
* node in the list is node. Tested by the address |
||||
|
* of the node, so it really must be the same |
||||
|
* address. |
||||
|
* \retval TRUE The node is the first node in the list. |
||||
|
* \retval FALSE The node is not the first node in the list. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Checks if node is at the beginning of the list. |
||||
|
*/ |
||||
|
#define GEN_LIST_BOL(type) \ |
||||
|
STATIC \ |
||||
|
int \ |
||||
|
list_ ## type ## _bol ( \ |
||||
|
list_ ## type ## _node_t *anchor, \ |
||||
|
list_ ## type ## _node_t *node) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
LIST_CHECK_NULL (anchor, "list_man.h", 70); \ |
||||
|
LIST_CHECK_NULL (node, "list_man.h", 71); \ |
||||
|
MAN_NODE_NO_ANCHOR_ERROR (anchor, 72); \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_man.h", 74, LIST_BOL_ERR); \ |
||||
|
\ |
||||
|
return anchor->next==node; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param anchor A pointer to the list anchor. |
||||
|
* \param node A pointer to a node in the list. |
||||
|
* \pre The \a anchor has to be not NULL and a valid |
||||
|
* anchor, the node has to be not NULL too. |
||||
|
* \return A boolean indicating if the last non-anchor |
||||
|
* node in the list is node. Tested by the address |
||||
|
* of the node, so it really must be the same |
||||
|
* address. |
||||
|
* \retval TRUE The node is the last node in the list. |
||||
|
* \retval FALSE The node is not the last node in the list. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Checks if node is at the end of the list. |
||||
|
*/ |
||||
|
#define GEN_LIST_EOL(type) \ |
||||
|
STATIC \ |
||||
|
int \ |
||||
|
list_ ## type ## _eol ( \ |
||||
|
list_ ## type ## _node_t *anchor, \ |
||||
|
list_ ## type ## _node_t *node) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
LIST_CHECK_NULL (anchor, "list_man.h", 88); \ |
||||
|
LIST_CHECK_NULL (node, "list_man.h", 89); \ |
||||
|
MAN_NODE_NO_ANCHOR_ERROR (anchor, 90); \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_man.h", 92, LIST_EOL_ERR); \ |
||||
|
\ |
||||
|
if (list_ ## type ## _isempty (anchor)) return -1; \ |
||||
|
return node->next==anchor; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param anchor A pointer to the list anchor. |
||||
|
* \pre The \a anchor has to be not NULL and a valid |
||||
|
* anchor. |
||||
|
* \return A boolean indicating if the last non-anchor |
||||
|
* node in the list is node. Tested by the address |
||||
|
* of the node, so it really must be the same |
||||
|
* address. |
||||
|
* \retval TRUE The node is the last node in the list. |
||||
|
* \retval FALSE The node is not the last node in the list. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Checks if node is at the end of the list. |
||||
|
*/ |
||||
|
#define GEN_LIST_ISEMPTY(type) \ |
||||
|
STATIC \ |
||||
|
int \ |
||||
|
list_ ## type ## _isempty (list_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
LIST_CHECK_NULL (anchor, "list_man.h", 103); \ |
||||
|
LIST_EXC_END ("list_man.h", 104, LIST_ISEMPTY_ERR); \ |
||||
|
\ |
||||
|
return (anchor->prev==anchor && anchor->next==anchor); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param cmp A pointer to a function that compares two |
||||
|
* variables of \a type. |
||||
|
* \pre None |
||||
|
* \return Nothing |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Set the compare function to \a cmp. |
||||
|
* |
||||
|
* This sets the compare function used by some functions generated |
||||
|
* for a list of the \a type datatype. This compare function has |
||||
|
* to work similar to strcmp. It should return either <0, ==0 or >0 |
||||
|
* depending on what comparator is lesser, greater or equal. |
||||
|
*/ |
||||
|
#define GEN_LIST_SET_CMP(type) \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
list_ ## type ## _set_cmp (list_ ## type ## _cmp_fptr cmp) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _compare = cmp; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param cmp A pointer to a function that compares two |
||||
|
* variables of \a type. |
||||
|
* \pre None |
||||
|
* \return Nothing |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Set the compare function to \a cmp. |
||||
|
* |
||||
|
* This sets the compare function used by some functions generated |
||||
|
* for a list of the \a type datatype. This compare function has |
||||
|
* to work similar to strcmp. It should return either <0, ==0 or >0 |
||||
|
* depending on what comparator is lesser, greater or equal. |
||||
|
*/ |
||||
|
#define GEN_LIST_SET_ELEM_FREE(type) \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
list_ ## type ## _set_elem_free ( \ |
||||
|
list_ ## type ## _elem_free_fptr efree) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _elem_free = efree; \ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
#define GEN_LIST_ELEM_FREE_IS_SET(type) \ |
||||
|
STATIC \ |
||||
|
long \ |
||||
|
list_ ## type ## _elem_free_is_set (void) \ |
||||
|
{ \ |
||||
|
return (long) list_ ## type ## _elem_free; \ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The functions for the given datatype that are described |
||||
|
* here are generated within the calling build file. |
||||
|
* |
||||
|
* \brief create functions neccesary to manage lists of the given \a type. |
||||
|
* |
||||
|
* Normally this is not called directly, but by GEN_LIST_IMPL() because this |
||||
|
* defined just a subset of all functions neccesarry to handle typesafe lists. |
||||
|
*/ |
||||
|
#define GEN_LIST_MANAGEMENT(type) \ |
||||
|
GEN_LIST_SET_CMP (type); \ |
||||
|
GEN_LIST_SET_ELEM_FREE (type); \ |
||||
|
GEN_LIST_ELEM_FREE_IS_SET (type) \ |
||||
|
GEN_LIST_NEW (type); \ |
||||
|
GEN_LIST_FREE (type); \ |
||||
|
GEN_LIST_COUNT (type); \ |
||||
|
GEN_LIST_BOL (type); \ |
||||
|
GEN_LIST_ISEMPTY (type); \ |
||||
|
GEN_LIST_EOL (type); |
||||
|
|
||||
|
|
||||
|
#endif /* LIST_MAN_H */ |
||||
@ -0,0 +1,308 @@ |
|||||
|
/** |
||||
|
* \file scot/list_mod.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Templates of functions to modify typesafe lists. |
||||
|
* |
||||
|
* Here are macro definitions that create functions to modify typesafe |
||||
|
* lists. That is read, write, insert, delete a.s.f. |
||||
|
* |
||||
|
* Normally the macros defined here will be never called directly but only |
||||
|
* via MACROS that group them in a sensefull way in scot/list_impl.h.\n |
||||
|
* \anchor onlyfunc_mod |
||||
|
* \attention |
||||
|
* All documentation here does document the functions that are created by |
||||
|
* the macros, as the macros themself are pretty easy and all used the same. |
||||
|
* They are called with a type, that MUST be one word (use typedef if needed) |
||||
|
* and generates the function defined with their value. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef LIST_MOD_H |
||||
|
#define LIST_MOD_H |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
#include <scot/list_impl.h> |
||||
|
#include <scot/memory.h> /* because we use functions from there */ |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param node a list_[type]_node_t* that should be checked for |
||||
|
* beeing an anchor. |
||||
|
* \param line the line where this MACRO is called. |
||||
|
* \pre a variable of type list_<type>_node_t* must exist. |
||||
|
* \return the code fragment |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief check for anchor. |
||||
|
* |
||||
|
* This checks if the given \a node is an anchor. If not it calls |
||||
|
* LIST_ERROR, which either raises an exception if exceptions are user |
||||
|
* or otherwise prints out an error message to stderr and aborts the |
||||
|
* program. |
||||
|
*/ |
||||
|
#define MOD_NODE_NO_ANCHOR_ERROR(node, line) \ |
||||
|
if ((node->e) != NULL) \ |
||||
|
LIST_ERROR ("list_mod.h", (line), NODE_NO_ANCHOR_ERR); |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_mod "here". |
||||
|
* |
||||
|
* \param node A pointer to a node in the list. |
||||
|
* \pre The \a node must be part of a correctly |
||||
|
* initialized list. |
||||
|
* \return The element saved in the node. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Retrive element from node. |
||||
|
* |
||||
|
* This function retrieves the element from a node of a list. |
||||
|
*/ |
||||
|
#define GEN_LIST_RETRIVE(type) \ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
list_ ## type ## _retrive (list_ ## type ## _node_t *node) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
LIST_CHECK_NULL (node, "list_mod.h", 18); \ |
||||
|
LIST_EXC_END ("list_mod.h", 19, LIST_RETR_ERR); \ |
||||
|
\ |
||||
|
return (type *) node->e; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_mod "here". |
||||
|
* |
||||
|
* \param node A pointer to a node in the list. |
||||
|
* \param e A pointer to a variable of the \a type, the |
||||
|
* list was created for. |
||||
|
* \pre The \a node must be part of a correctly |
||||
|
* initialized list. \a e must not be NULL. |
||||
|
* \return Nothing |
||||
|
* \post The element of \a node is \a e. |
||||
|
* |
||||
|
* \brief Set element od node. |
||||
|
* |
||||
|
* This function sets the element from a node of a list. |
||||
|
*/ |
||||
|
#define GEN_LIST_SET(type) \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
list_ ## type ## _set ( \ |
||||
|
list_ ## type ## _node_t *node, \ |
||||
|
const type *e) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
LIST_CHECK_NULL (node, "list_mod.h", 33); \ |
||||
|
LIST_CHECK_NULL (e, "list_mod.h", 34); \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_mod.h", 36, LIST_SET_ERR); \ |
||||
|
\ |
||||
|
node->e = e; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_mod "here". |
||||
|
* |
||||
|
* \param node A pointer to a node in the list. |
||||
|
* \param e A pointer to a variable of the \a type, the |
||||
|
* list was created for. |
||||
|
* \pre The \a node must be part of a correctly |
||||
|
* initialized list. |
||||
|
* \a e must not be NULL. |
||||
|
* \return The node of the inserted element. |
||||
|
* \post List has one new node containing \a e. |
||||
|
* |
||||
|
* \brief Inserts a new node with element \a e into the list. |
||||
|
* |
||||
|
* This function creates a new list node and initializes it with |
||||
|
* \a e. Then this new node will be inserted behind \a node. |
||||
|
*/ |
||||
|
#define GEN_LIST_INSERT(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _insert ( \ |
||||
|
list_ ## type ## _node_t *node, \ |
||||
|
const type *e) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *ret; \ |
||||
|
\ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *new_node; \ |
||||
|
\ |
||||
|
LIST_CHECK_NULL (node, "list_mod.h", 54); \ |
||||
|
LIST_CHECK_NULL (e, "list_mod.h", 55); \ |
||||
|
\ |
||||
|
new_node = (list_ ## type ## _node_t *) \ |
||||
|
LIST_MALLOC (sizeof (list_ ## type ## _node_t), \ |
||||
|
"list_mod.h", 58); \ |
||||
|
\ |
||||
|
new_node->e = e; \ |
||||
|
new_node->prev = node; \ |
||||
|
new_node->next = node->next; \ |
||||
|
node->next->prev = new_node; \ |
||||
|
node->next = new_node; \ |
||||
|
\ |
||||
|
ret = new_node; \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_mod.h", 69, LIST_INSERT_ERR); \ |
||||
|
\ |
||||
|
return ret; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_mod "here". |
||||
|
* |
||||
|
* \param node A pointer to a node in the list. |
||||
|
* \pre The \a node must be part of a correctly |
||||
|
* initialized list. |
||||
|
* \return The next node behind the deleted one. |
||||
|
* \post The \a node is removed from the list and |
||||
|
* freed. |
||||
|
* |
||||
|
* \brief Deletes a new node with element \a e into the list. |
||||
|
* |
||||
|
* This function deletes a node from the list it is in. The node |
||||
|
* will be freed but by default NOT the element. Anyway, one can set |
||||
|
* a free function for elements of the list. This should free any |
||||
|
* resource the element has reserved. |
||||
|
* This function can be set with |
||||
|
* \link list_man.h::GEN_LIST_SET_ELEM_FREE |
||||
|
* list_[type]_set_elem_free ()\endlink |
||||
|
* and if set, is called by list_[type]_delete(). If such a function |
||||
|
* was set and one wants to reset to default behaviour (not to delete any |
||||
|
* element) one can pass NULL to \link list_man.h::GEN_LIST_SET_ELEM_FREE |
||||
|
* list_[type]_set_elem_free ()\endlink. |
||||
|
*/ |
||||
|
#define GEN_LIST_DELETE(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _delete (list_ ## type ## _node_t *node) \ |
||||
|
{ \ |
||||
|
type *e; \ |
||||
|
list_ ## type ## _node_t *prev, \ |
||||
|
*next; \ |
||||
|
\ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
if (list_ ## type ## _isempty (node)) \ |
||||
|
LIST_WARNING ("list_mod.h", 86, DEL_ON_EMPTY_LIST_WRN); \ |
||||
|
\ |
||||
|
e = (type *) node->e; \ |
||||
|
\ |
||||
|
prev = node->prev; \ |
||||
|
next = node->next; \ |
||||
|
prev->next = next; \ |
||||
|
next->prev = prev; \ |
||||
|
\ |
||||
|
if (list_ ## type ## _elem_free != NULL && e != NULL) \ |
||||
|
list_ ## type ## _elem_free (e); \ |
||||
|
\ |
||||
|
SCOT_MEM_FREE (node); \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_mod.h", 101, LIST_DELETE_ERR); \ |
||||
|
\ |
||||
|
return next; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_mod "here". |
||||
|
* |
||||
|
* \param anchor1 A pointer to the first list anchor. |
||||
|
* \param anchor2 A pointer to the second list anchor. |
||||
|
* \pre Both, \a anchor1 and \a anchor2 must be |
||||
|
* valid list_anchors. |
||||
|
* \return The anchor of the new concatenated list. |
||||
|
* \post A new list was created that contains both |
||||
|
* given lists. The anchor of at least one of the |
||||
|
* given lists is no longer valid and should no |
||||
|
* longer be used. In fact only the returned |
||||
|
* anchor is garantied to point to a valid list. |
||||
|
* |
||||
|
* \brief Concatenates two lists. |
||||
|
* |
||||
|
* This function joins the given two list to one. This will be done |
||||
|
* partly destructive...that is, at least one of the old anchors |
||||
|
* will be deleted. |
||||
|
*/ |
||||
|
#define GEN_LIST_CONCAT(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _concat ( \ |
||||
|
list_ ## type ## _node_t *anchor1, \ |
||||
|
list_ ## type ## _node_t *anchor2) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
LIST_CHECK_NULL (anchor1, "list_mod.h", 115); \ |
||||
|
MOD_NODE_NO_ANCHOR_ERROR (anchor1, 116); \ |
||||
|
LIST_CHECK_NULL (anchor2, "list_mod.h", 117); \ |
||||
|
MOD_NODE_NO_ANCHOR_ERROR (anchor2, 118); \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_mod.h", 120, LIST_CONCAT_ERR); \ |
||||
|
\ |
||||
|
if (list_ ## type ## _isempty (anchor1)) \ |
||||
|
return anchor2; \ |
||||
|
\ |
||||
|
if (list_ ## type ## _isempty (anchor2)) \ |
||||
|
return anchor1; \ |
||||
|
\ |
||||
|
anchor2->next->prev = anchor1->prev; \ |
||||
|
anchor2->prev->next = anchor1; \ |
||||
|
anchor1->prev->next = anchor2->next; \ |
||||
|
anchor1->prev = anchor2->prev; \ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The functions for the given datatype that are described |
||||
|
* here are generated within the calling build file. |
||||
|
* |
||||
|
* \brief create functions neccesary to modify lists of the given \a type. |
||||
|
* |
||||
|
* Normally this is not called directly, but by GEN_LIST_IMPL() because this |
||||
|
* defines just a subset of all functions neccesarry to handle typesafe lists. |
||||
|
*/ |
||||
|
#define GEN_LIST_MODIFY(type) \ |
||||
|
GEN_LIST_RETRIVE (type); \ |
||||
|
GEN_LIST_SET (type); \ |
||||
|
GEN_LIST_INSERT (type); \ |
||||
|
GEN_LIST_DELETE (type); \ |
||||
|
GEN_LIST_CONCAT (type); |
||||
|
|
||||
|
|
||||
|
|
||||
|
#endif /* LIST_MOD_H */ |
||||
@ -0,0 +1,290 @@ |
|||||
|
/** |
||||
|
* \file scot/list_nav.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Templates of functions to navigate within typesafe lists. |
||||
|
* |
||||
|
* Here are macro definitions that create functions to navigate within |
||||
|
* typesafe lists. That is get next node, get first node a.s.f |
||||
|
* |
||||
|
* Normally the macros defined here will be never called directly but only |
||||
|
* via MACROS that group them in a sensefull way in scot/list_impl.h.\n |
||||
|
* \anchor onlyfunc_nav |
||||
|
* \attention |
||||
|
* All documentation here does document the functions that are created by |
||||
|
* the macros, as the macros themself are pretty easy and all used the same. |
||||
|
* They are called with a type, that MUST be one word (use typedef if needed) |
||||
|
* and generates the function defined with their value. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef LIST_NAV_H |
||||
|
#define LIST_NAV_H |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
#include <scot/list_impl.h> |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param node a list_[type]_node_t* that should be checked for |
||||
|
* beeing an anchor. |
||||
|
* \param line the line where this MACRO is called. |
||||
|
* \pre a variable of type list_[type]_node_t* must exist. |
||||
|
* \return the code fragment |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief check for anchor. |
||||
|
* |
||||
|
* This checks if the given \a node is an anchor. If not it calls |
||||
|
* LIST_ERROR, which either raises an exception if exceptions are user |
||||
|
* or otherwise prints out an error message to stderr and aborts the |
||||
|
* program. |
||||
|
*/ |
||||
|
#define NAV_NODE_NO_ANCHOR_ERROR(node, line) \ |
||||
|
if ((node->e) != NULL) \ |
||||
|
LIST_ERROR ("list_nav.h", (line), NODE_NO_ANCHOR_ERR); |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param anchor A pointer to the list anchor. |
||||
|
* \pre The \a anchor has to be not NULL and a valid |
||||
|
* anchor. |
||||
|
* \return The first node in the list, that is normally |
||||
|
* the anchor, thus this is pretty useless. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Returns the first element in the list, that is the anchor... |
||||
|
* pathetic... |
||||
|
*/ |
||||
|
#define GEN_LIST_FRONT(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _front (list_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
LIST_CHECK_NULL (anchor, "list_nav.h", 20); \ |
||||
|
NAV_NODE_NO_ANCHOR_ERROR (anchor, 21); \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_nav.h", 23, LIST_FRONT_ERR); \ |
||||
|
\ |
||||
|
return anchor; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param anchor A pointer to the list anchor. |
||||
|
* \pre The \a anchor has to be not NULL and a valid |
||||
|
* anchor. |
||||
|
* \return The last node in the list. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Get the last node in the list. |
||||
|
*/ |
||||
|
#define GEN_LIST_LAST(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _last (list_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
LIST_CHECK_NULL (anchor, "list_nav.h", 35); \ |
||||
|
NAV_NODE_NO_ANCHOR_ERROR (anchor, 36); \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_nav.h", 38, LIST_LAST_ERR); \ |
||||
|
\ |
||||
|
return anchor->prev; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param node A pointer to a node in the list. |
||||
|
* \pre The node has to be not NULL and should be in |
||||
|
* a linked list. |
||||
|
* \return The next node after the given node. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Get the next node in the list. |
||||
|
*/ |
||||
|
#define GEN_LIST_NEXT(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _next (list_ ## type ## _node_t *node) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
LIST_CHECK_NULL (node, "list_nav.h", 49); \ |
||||
|
LIST_EXC_END ("list_nav.h", 50, LIST_NEXT_ERR); \ |
||||
|
\ |
||||
|
return node->next; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param node A pointer to a node in the list. |
||||
|
* \pre The node has to be not NULL and should be in |
||||
|
* a linked list. |
||||
|
* \return The previous node after the given node. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Get the previous node in the list. |
||||
|
*/ |
||||
|
#define GEN_LIST_PREV(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _prev (list_ ## type ## _node_t *node) \ |
||||
|
{ \ |
||||
|
LIST_EXC_START \ |
||||
|
LIST_CHECK_NULL (node, "list_nav.h", 61); \ |
||||
|
LIST_EXC_END ("list_nav.h", 62, LIST_PREV_ERR); \ |
||||
|
\ |
||||
|
return node->prev; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param anchor A pointer to the list anchor. |
||||
|
* \param e A pointer to a variable of the \a type, the |
||||
|
* list was created for. |
||||
|
* \pre The \a anchor has to be not NULL and a valid |
||||
|
* anchor.\a e must not be NULL. |
||||
|
* \return The node that contains \a e. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Find the node in the list that contains \a e. |
||||
|
*/ |
||||
|
#define GEN_LIST_FIND(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _find ( \ |
||||
|
list_ ## type ## _node_t *anchor, \ |
||||
|
const type *e) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *ret = NULL; \ |
||||
|
\ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *node; \ |
||||
|
\ |
||||
|
LIST_CHECK_NULL (anchor, "list_nav.h", 80); \ |
||||
|
NAV_NODE_NO_ANCHOR_ERROR (anchor, 81); \ |
||||
|
\ |
||||
|
node = anchor; \ |
||||
|
while (! list_ ## type ## _eol (anchor, node)) \ |
||||
|
{ \ |
||||
|
node = node->next; \ |
||||
|
\ |
||||
|
if (node->e != NULL) \ |
||||
|
if (list_ ## type ## _compare (e, node->e) == 0) \ |
||||
|
ret = node; \ |
||||
|
} \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_nav.h", 93, LIST_FIND_ERR); \ |
||||
|
\ |
||||
|
return ret; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_man "here". |
||||
|
* |
||||
|
* \param node A pointer to a node in the list. |
||||
|
* \pre The node has to be not NULL and should be in |
||||
|
* a linked list. |
||||
|
* \return The anchor of the list, the \a node is in. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Get the anchor of the list. |
||||
|
*/ |
||||
|
#define GEN_LIST_FIND_ANCHOR(type) \ |
||||
|
STATIC \ |
||||
|
list_ ## type ## _node_t * \ |
||||
|
list_ ## type ## _find_anchor ( \ |
||||
|
list_ ## type ## _node_t *entry) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *ret = NULL; \ |
||||
|
\ |
||||
|
LIST_EXC_START \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *node; \ |
||||
|
\ |
||||
|
LIST_CHECK_NULL (entry, "list_nav.h", 110); \ |
||||
|
\ |
||||
|
node = entry; \ |
||||
|
if (node->e == NULL) \ |
||||
|
ret = node; \ |
||||
|
\ |
||||
|
while (! list_ ## type ## _eol (entry, node)) \ |
||||
|
{ \ |
||||
|
node = node->next; \ |
||||
|
\ |
||||
|
if (node->e == NULL) \ |
||||
|
ret = node; \ |
||||
|
} \ |
||||
|
\ |
||||
|
if (ret == NULL) \ |
||||
|
LIST_ERROR ("list_nav.h", 125, MALFORMED_LIST_ERR); \ |
||||
|
} \ |
||||
|
LIST_EXC_END ("list_nav.h", 127, LIST_FIND_ANCHOR_ERR); \ |
||||
|
\ |
||||
|
return NULL; \ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The functions for the given datatype that are described |
||||
|
* here are generated within the calling build file. |
||||
|
* |
||||
|
* \brief create functions neccesary to modify lists of the given \a type. |
||||
|
* |
||||
|
* Normally this is not called directly, but by GEN_LIST_IMPL() because this |
||||
|
* defines just a subset of all functions neccesarry to handle typesafe lists. |
||||
|
*/ |
||||
|
#define GEN_LIST_NAVIGATION(type) \ |
||||
|
GEN_LIST_FRONT (type); \ |
||||
|
GEN_LIST_LAST (type); \ |
||||
|
GEN_LIST_NEXT (type); \ |
||||
|
GEN_LIST_PREV (type); \ |
||||
|
GEN_LIST_FIND (type); \ |
||||
|
GEN_LIST_FIND_ANCHOR (type); |
||||
|
|
||||
|
|
||||
|
|
||||
|
#endif /* LIST_NAV_H */ |
||||
@ -0,0 +1,101 @@ |
|||||
|
/** |
||||
|
* \file scot/list_proto.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief This generates all prototypes needed for typesafe lists. |
||||
|
* |
||||
|
* This combines the macro definitions in \link scot/list_type_proto.h |
||||
|
* scot/list_type_proto.h \endlink and \link scot/list_func_proto.h |
||||
|
* scot/list_func_proto.h \endlink. |
||||
|
* Additionally defines for all errornumbers that list will create can be |
||||
|
* found here. |
||||
|
* GEN_LIST_PROTO is normally called in a header file that describes a |
||||
|
* new Datatype and also wants lists of it. |
||||
|
* By doing this the complete interface to lists of that datatype is |
||||
|
* produced. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef LIST_PROTO_H |
||||
|
#define LIST_PROTO_H |
||||
|
|
||||
|
#include <scot/list_type_proto.h> |
||||
|
#include <scot/list_func_proto.h> |
||||
|
|
||||
|
/** \brief errnum if list_[type]_new() failes*/ |
||||
|
#define LIST_NEW_ERR 0x00 |
||||
|
/** \brief errnum if list_[type]_free() failes*/ |
||||
|
#define LIST_FREE_ERR 0x01 |
||||
|
/** \brief errnum if list_[type]_bol() failes*/ |
||||
|
#define LIST_BOL_ERR 0x02 |
||||
|
/** \brief errnum if list_[type]_eol() failes*/ |
||||
|
#define LIST_EOL_ERR 0x03 |
||||
|
/** \brief errnum if list_[type]_isempty() failes*/ |
||||
|
#define LIST_ISEMPTY_ERR 0x04 |
||||
|
/** \brief errnum if list_[type]_front() failes*/ |
||||
|
#define LIST_FRONT_ERR 0x05 |
||||
|
/** \brief errnum if list_[type]_last() failes*/ |
||||
|
#define LIST_LAST_ERR 0x06 |
||||
|
/** \brief errnum if list_[type]_next() failes*/ |
||||
|
#define LIST_NEXT_ERR 0x07 |
||||
|
/** \brief errnum if list_[type]_prev() failes*/ |
||||
|
#define LIST_PREV_ERR 0x08 |
||||
|
/** \brief errnum if list_[type]_find() failes*/ |
||||
|
#define LIST_FIND_ERR 0x09 |
||||
|
/** \brief errnum if list_[type]_find_anchor() failes*/ |
||||
|
#define LIST_FIND_ANCHOR_ERR 0x0A |
||||
|
/** \brief errnum if list_[type]_retrive() failes*/ |
||||
|
#define LIST_RETR_ERR 0x0B |
||||
|
/** \brief errnum if list_[type]_set() failes*/ |
||||
|
#define LIST_SET_ERR 0x0C |
||||
|
/** \brief errnum if list_[type]_insert() failes*/ |
||||
|
#define LIST_INSERT_ERR 0x0D |
||||
|
/** \brief errnum if list_[type]_delete() failes*/ |
||||
|
#define LIST_DELETE_ERR 0x0E |
||||
|
/** \brief errnum if list_[type]_concat() failes*/ |
||||
|
#define LIST_CONCAT_ERR 0x0F |
||||
|
/** \brief errnum if list_[type]_count() failes*/ |
||||
|
#define LIST_COUNT_ERR 0x10 |
||||
|
|
||||
|
/** \brief errnum if node is no anchor*/ |
||||
|
#define NODE_NO_ANCHOR_ERR 0x11 |
||||
|
/** \brief errnum if list has no anchor*/ |
||||
|
#define MALFORMED_LIST_ERR 0x12 |
||||
|
|
||||
|
/** \brief warning if delete on empty list*/ |
||||
|
#define DEL_ON_EMPTY_LIST_WRN 0x01 |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The typedefs, struct declaration and function prototypes |
||||
|
* for functions to lists for the given datatype are |
||||
|
* generated within the calling build file. |
||||
|
* |
||||
|
* \brief this creates all typdefs, declarations and prototypes needed for a |
||||
|
* typesafe list of a given \a type. This is normally calles within |
||||
|
* a header file. |
||||
|
*/ |
||||
|
#define GEN_LIST_PROTO(type) \ |
||||
|
GEN_LIST_TYPE_PROTO (type) \ |
||||
|
GEN_LIST_FUNC_PROTO (type) |
||||
|
|
||||
|
#endif /* LIST_PROTO_H */ |
||||
@ -0,0 +1,64 @@ |
|||||
|
/** |
||||
|
* \file scot/list_type_proto.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro that creates the datatype for handling linked lists. |
||||
|
* |
||||
|
* The macros here create all datatype prototypes typedefs declarations to |
||||
|
* the implementations created by the macros in |
||||
|
* \link scot/list_impl.h scot/list_impl.h\endlink. |
||||
|
* These macros are normally not called directly within your code but |
||||
|
* through \link scot/list_proto.h::GEN_LIST_PROTO GEN_LIST_PROTO\endlink. |
||||
|
* This is because normally one did not only |
||||
|
* want the datatypes but also the interface declaration to them. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef LIST_TYPE_PROTO_H |
||||
|
#define LIST_TYPE_PROTO_H |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* \return Nothing |
||||
|
* \post The datatype prototypes for lists of the given |
||||
|
* datatype are created. |
||||
|
* |
||||
|
* \brief Datatype prototypes to lists. |
||||
|
* |
||||
|
* This creates the prototypes of the datatypes needed to use the |
||||
|
* list interface. |
||||
|
* |
||||
|
* Normally this is not called directly, but by |
||||
|
* \link scot/list_proto.h::GEN_LIST_PROTO GEN_LIST_PROTO()\endlink |
||||
|
* because it is also neccesary to create the interface to this |
||||
|
* datatypes for working lists. |
||||
|
*/ |
||||
|
#define GEN_LIST_TYPE_PROTO(type) \ |
||||
|
struct list_ ## type ## _node_t; \ |
||||
|
typedef struct list_ ## type ## _node_t \ |
||||
|
list_ ## type ## _node_t; \ |
||||
|
\ |
||||
|
typedef int (*list_ ## type ## _cmp_fptr) ( \ |
||||
|
const type *, \ |
||||
|
const type *); \ |
||||
|
\ |
||||
|
typedef void (*list_ ## type ## _elem_free_fptr) (type *); |
||||
|
|
||||
|
#endif /* LIST_TYPE_PROTO_H */ |
||||
@ -0,0 +1,71 @@ |
|||||
|
/* |
||||
|
* dir.h: as one might suggest here are definitions and prototypes for |
||||
|
* posix/dir.c |
||||
|
* |
||||
|
* Copyright (C) 2006 Georg Steffers |
||||
|
* |
||||
|
* Author: Georg Steffers [GST] <georg.steffers@aschendorff.de> |
||||
|
* Developer: |
||||
|
* |
||||
|
* Changes (for this file only): |
||||
|
* (2006-06-12) [GST] Started this changelog...well the program is |
||||
|
* ready since some weeks right now. |
||||
|
*/ |
||||
|
#ifndef DIR_H |
||||
|
#define DIR_H |
||||
|
|
||||
|
#include <sys/stat.h> |
||||
|
#include <dirent.h> |
||||
|
|
||||
|
#include <scot/dir_common.h> |
||||
|
#include <scot/event_listener.h> |
||||
|
|
||||
|
struct scot_dir |
||||
|
{ |
||||
|
struct scot_event_listener el; |
||||
|
|
||||
|
DIR * handle; |
||||
|
const char * path; |
||||
|
|
||||
|
int notify_handle; |
||||
|
}; |
||||
|
|
||||
|
/* abstraction for file information and an directory handle */ |
||||
|
#define FILE_DATA struct dirent_stat |
||||
|
#define DIR_HANDLE DIR * |
||||
|
/* #define DIR_HANDLE struct scot_dir * */ |
||||
|
|
||||
|
/* abstraction for checking if a file is a directory */ |
||||
|
#define IS_DIRECTORY(file_data) (S_ISDIR ((file_data).stat.st_mode)) |
||||
|
|
||||
|
/* abstraction for getting the filename of a directory entry. */ |
||||
|
#define DIRENT_FNAME(file_data) ((file_data).file->d_name) |
||||
|
|
||||
|
/* !!!FIXME!!! is there any place where this is already defined in posix? */ |
||||
|
#ifndef MAX_PATH |
||||
|
# define MAX_PATH 2000 |
||||
|
#endif /* MAX_PATH */ |
||||
|
|
||||
|
/* structure for all available information about the directory entry. */ |
||||
|
struct dirent_stat |
||||
|
{ |
||||
|
char path [MAX_PATH+1]; |
||||
|
struct dirent * file; |
||||
|
struct stat stat; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/* the last parameter is posix specific. It defines if stat should |
||||
|
* follow symlinks or not. Under Windows it is ignored. */ |
||||
|
DIR_HANDLE get_dir_first (const char *, FILE_DATA *, int); |
||||
|
int get_dir_next (DIR_HANDLE, const char *, FILE_DATA *, int); |
||||
|
|
||||
|
/* |
||||
|
DIR_HANDLE scot_dir_new (const char *); |
||||
|
void scot_dir_free (DIR_HANDLE); |
||||
|
|
||||
|
int get_dir_first (DIR_HANDLE, FILE_DATA *, int); |
||||
|
int get_dir_next (DIR_HANDLE, FILE_DATA *, int); |
||||
|
*/ |
||||
|
|
||||
|
#endif /* DIR_H */ |
||||
@ -0,0 +1,32 @@ |
|||||
|
/*************************************************************************** |
||||
|
* memory.h: Prototypes for default memory operations like memcpy and thus * |
||||
|
* on a win32 system nearly all CRT functions (CRT is the * |
||||
|
* windows C RunTime, that is the normal libC) aren't thread- * |
||||
|
* safe. As i build up tests this causes problems for example * |
||||
|
* with strcpy. So i decided to write wrapper that use non CRT * |
||||
|
* functions on Windows and normal libC ones on a posix system. * |
||||
|
* * |
||||
|
* Author: Georg Steffers <georg@steffers.org> * |
||||
|
* Date: 03/06/2006 * |
||||
|
***************************************************************************/ |
||||
|
#ifndef MEMORY_H |
||||
|
#define MEMORY_H |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
#include <scot_common.h> |
||||
|
|
||||
|
#define SCOT_MEM_GET malloc |
||||
|
#define SCOT_MEM_FREE(p) if ((p)) {free((p)); (p)=NULL;} |
||||
|
#define SCOT_MEM_COPY memcpy |
||||
|
#define SCOT_MEM_MOVE memmove |
||||
|
#define SCOT_MEM_FILL memset |
||||
|
#define SCOT_MEM_ZERO(p,s) memset ((p), 0, (s)) |
||||
|
#define SCOT_STR_LENGTH strlen |
||||
|
#define SCOT_STR_COPY strcpy |
||||
|
#define SCOT_STRN_COPY strncpy |
||||
|
#define SCOT_STR_CHAR strchr |
||||
|
#define SCOT_STRR_CHAR strrchr |
||||
|
|
||||
|
#endif /* MEMORY_H */ |
||||
@ -0,0 +1,9 @@ |
|||||
|
#ifndef SCOT_TYPES_H |
||||
|
#define SCOT_TYPES_H |
||||
|
|
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
typedef ssize_t SSIZE_T; |
||||
|
typedef size_t SIZE_T; |
||||
|
|
||||
|
#endif /* SCOT_TYPES_H */ |
||||
@ -0,0 +1,102 @@ |
|||||
|
/* |
||||
|
* used for threadsafety within exception |
||||
|
* actually only pthread is supported |
||||
|
*/ |
||||
|
#ifndef THREAD_H |
||||
|
#define THREAD_H |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <pthread.h> |
||||
|
|
||||
|
#include <scot/scot_int.h> |
||||
|
|
||||
|
#ifndef INFINITE |
||||
|
# define INFINITE 0 |
||||
|
#endif /* INFINITE */ |
||||
|
|
||||
|
|
||||
|
#define JOIN_OK 0x00 |
||||
|
#define JOIN_TIMEOUT 0x01 |
||||
|
#define JOIN_ERROR 0x02 |
||||
|
|
||||
|
/* |
||||
|
* i guess it is possible to write mutex code that uses cond |
||||
|
* elements to timeout on lock, but right now i have no clear |
||||
|
* idea of how to do this. The following thoughts i had: |
||||
|
* - create a struct that holds a pthread_mutex_t and a pthread_cond_t |
||||
|
* for every mutex. |
||||
|
* - lock mutexes only by calling pthread_cond_timedwait |
||||
|
* And here starts the problem...to do a cond_timedwait i need to ensure |
||||
|
* that the mutex is already locked...well and then a question i have not |
||||
|
* clearyfied, if a thread ends, will all locks on mutexes be removed? |
||||
|
* I guess so, but i did not test it. And an even more important question, |
||||
|
* is it possible to write cleanup-code that guarantees that a |
||||
|
* pthread_cond_signal is called for every mutex the thread holds... |
||||
|
* well, we will end up with the requirement that the programmer has to |
||||
|
* call a release mutex function before ending a thread and if the programmer |
||||
|
* forgets that the behaviour of out code is unspecified |
||||
|
* Right now i will not support timeouts on mutex-locks and to be consistent |
||||
|
* it is not supported on win32 either, also it would be much easier to |
||||
|
* implement there. |
||||
|
*/ |
||||
|
#define MUTEX_LOCK_OK 0x00 |
||||
|
#define MUTEX_LOCK_ERROR 0x02 |
||||
|
|
||||
|
#define THREAD_T pthread_t |
||||
|
#define THREAD_ID_T pthread_t |
||||
|
#define THREAD_ID pthread_self () |
||||
|
#define SELF_THREAD pthread_self () |
||||
|
#define THREAD_EQUAL pthread_equal |
||||
|
#define NEW_THREAD(th,f, a) thread_new ((th), (f), (a)) |
||||
|
#define END_THREAD thread_end |
||||
|
#define DETACH_THREAD(thread) pthread_detach ((thread)) |
||||
|
#define CANCEL_THREAD(thread) pthread_cancel ((thread)) |
||||
|
#define EXIT_THREAD(retval) pthread_exit ((void *) (retval)) |
||||
|
#define JOIN_THREAD thread_join |
||||
|
#define THREAD_CANCEL_ENABLE pthread_setcancelstate \ |
||||
|
(PTHREAD_CANCEL_ENABLE, NULL) |
||||
|
#define THREAD_CANCEL_DISABLE pthread_setcancelstate \ |
||||
|
(PTHREAD_CANCEL_DISABLE, NULL) |
||||
|
#define THREAD_CANCEL_ASYNC pthread_setcanceltype \ |
||||
|
(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) |
||||
|
#define THREAD_CANCEL_DEFER pthread_setcanceltype \ |
||||
|
(PTHREAD_CANCEL_DEFERRED, NULL) |
||||
|
#define THREAD_TESTCANCEL pthread_testcancel () |
||||
|
#define T_PROC_RET void * |
||||
|
|
||||
|
#define THREAD_MUTEX_T pthread_mutex_t |
||||
|
#define NEW_THREAD_MUTEX thread_mutex_new |
||||
|
#define FREE_THREAD_MUTEX pthread_mutex_destroy |
||||
|
#define LOCK_THREAD_MUTEX thread_mutex_lock |
||||
|
#define UNLOCK_THREAD_MUTEX pthread_mutex_unlock |
||||
|
|
||||
|
#define THREAD_COND_T pthread_cond_t |
||||
|
#define THREAD_COND_CS_T pthread_mutex_t |
||||
|
#define GET_THREAD_COND(c) (*(c) = PTHREAD_COND_INITIALIZER) |
||||
|
#define GET_THREAD_COND_CS(c) (*(c) = PTHREAD_MUTEX_INITIALIZER) |
||||
|
#define NEW_THREAD_COND thread_cond_new |
||||
|
#define NEW_THREAD_COND_CS thread_mutex_new |
||||
|
#define FREE_THREAD_COND pthread_cond_destroy |
||||
|
#define FREE_THREAD_COND_CS pthread_mutex_destroy |
||||
|
#define THREAD_COND_ENTER_CS(cs) pthread_mutex_lock ((cs)) |
||||
|
#define THREAD_COND_LEAVE_CS(cs) pthread_mutex_unlock ((cs)) |
||||
|
#define SIGNAL_THREAD_COND(cond) pthread_cond_signal ((cond)) |
||||
|
#define BCAST_THREAD_COND(cond) pthread_cond_broadcast ((cond)) |
||||
|
#define WAIT_THREAD_COND(cond, cs, t) thread_cond_wait ((cond), (cs), t) |
||||
|
|
||||
|
#define THREAD_ATEXIT_BEGIN pthread_cleanup_push |
||||
|
#define THREAD_ATEXIT_END pthread_cleanup_pop |
||||
|
|
||||
|
typedef T_PROC_RET (*scot_thread_entry_fptr) (void *); |
||||
|
|
||||
|
void thread_new (THREAD_T *, T_PROC_RET (*)(void *), void*); |
||||
|
int thread_join (THREAD_T, uint32_t); |
||||
|
void thread_end (THREAD_T, uint32_t); |
||||
|
void thread_mutex_new (THREAD_MUTEX_T *); |
||||
|
void thread_cond_new (THREAD_COND_T *); |
||||
|
int thread_mutex_lock (THREAD_MUTEX_T *); |
||||
|
|
||||
|
int thread_cond_wait (THREAD_COND_T *, |
||||
|
THREAD_COND_CS_T *, uint32_t); |
||||
|
|
||||
|
#endif /* THREAD_H */ |
||||
@ -0,0 +1,69 @@ |
|||||
|
/** |
||||
|
* \file scot/queue.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro which produce all prototypes and implementations for |
||||
|
* handling queues based on linked lists by Templates. |
||||
|
* |
||||
|
* This is the toplevel template file for queues based on typesafe lists. |
||||
|
* It is quite simple. It just defines one MACRO which in turn calls two |
||||
|
* other macros to generate all that is needed for queue-handling of a queue |
||||
|
* to a given type. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef QUEUE_H |
||||
|
#define QUEUE_H |
||||
|
|
||||
|
#include <scot/queue_proto.h> |
||||
|
#include <scot/queue_impl.h> |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST(type) has to be called for the list functions, |
||||
|
* as queues depend on these. |
||||
|
* \return Nothing |
||||
|
* \post The complete framework of functions, types, globals |
||||
|
* prototypes and definitions to handle queues based on |
||||
|
* typesave |
||||
|
* lists for the given datatype are generated within the |
||||
|
* calling build file. |
||||
|
* |
||||
|
* \brief create complete framework to handle queues based on typesafe lists. |
||||
|
* |
||||
|
* This macro first colls GEN_QUEUE_PROTO() to create all prototypes |
||||
|
* neccesary for handling queues of the given \a type. And then it calls |
||||
|
* GEN_QUEUE_IMPL() to also create the neccesary definitions and |
||||
|
* implementations.\ |
||||
|
* Normally this macro is only called if one only wants to have queues |
||||
|
* of the given type in a single c source file and nowhere else. Normally |
||||
|
* this is then used in conjunction with a previous define of GEN_LOCAL, |
||||
|
* that tells GEN_QUEUE() and the subsequent macros to generate the functions |
||||
|
* as static.\n |
||||
|
* If one wants to used queues of the given type in several places of the |
||||
|
* project one would normally call GEN_QUEUE_PROTO() in a h file and |
||||
|
* GEN_QUEUE_IMPL() in the c file that does the implementation of that |
||||
|
* h file (without GEN_LOCAL). |
||||
|
*/ |
||||
|
#define GEN_QUEUE(type) \ |
||||
|
GEN_QUEUE_PROTO (type) \ |
||||
|
GEN_QUEUE_IMPL (type) |
||||
|
|
||||
|
#endif /* QUEUE_H */ |
||||
@ -0,0 +1,89 @@ |
|||||
|
/** |
||||
|
* \file scot/queue_func_proto.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro that produces function prototypes for handling queues |
||||
|
* based on linked lists. |
||||
|
* |
||||
|
* The macros here create all function prototypes to |
||||
|
* the implementations created by the macros in |
||||
|
* \link scot/queue_impl.h scot/queue_impl.h\endlink. |
||||
|
* These macros are normally not called directly within your code but |
||||
|
* through \link scot/queue_proto.h::GEN_QUEUE_PROTO GEN_QUEUE_PROTO\endlink. |
||||
|
* This is because to use the interface declaration |
||||
|
* provided here one will also need the typedefs and datatype prototypes. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef QUEUE_FUNC_PROTO_H |
||||
|
#define QUEUE_FUNC_PROTO_H |
||||
|
|
||||
|
|
||||
|
#ifdef GEN_LOCAL |
||||
|
# define STATIC static |
||||
|
#else |
||||
|
# define STATIC |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST_FUNC_PROTO should have bin called previously |
||||
|
* in one or the other way. |
||||
|
* \return Nothing |
||||
|
* \post All function prototypes for a queue of the given |
||||
|
* datatype are created. |
||||
|
* |
||||
|
* \brief This creates the prototypes to all queue functions |
||||
|
* |
||||
|
* This creates all the prototypes to the functions that are created by |
||||
|
* \link scot/queue_impl.h::GEN_QUEUE_IMPL GEN_QUEUE_IMPL\endlink in |
||||
|
* \link scot/queue_impl.h scot/queue_impl.h\endlink. |
||||
|
* This provides one with the complete interface to the queue of the given |
||||
|
* datatype. |
||||
|
*/ |
||||
|
#define GEN_QUEUE_FUNC_PROTO(type) \ |
||||
|
STATIC \ |
||||
|
queue_ ## type ## _node_t * \ |
||||
|
queue_ ## type ## _new ( \ |
||||
|
queue_ ## type ## _node_t *); \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
queue_ ## type ## _free ( \ |
||||
|
queue_ ## type ## _node_t *); \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
queue_ ## type ## _node_t * \ |
||||
|
queue_ ## type ## _enqueue ( \ |
||||
|
queue_ ## type ## _node_t *, \ |
||||
|
const type *); \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
queue_ ## type ## _dequeue ( \ |
||||
|
queue_ ## type ## _node_t *); \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
queue_ ## type ## _top ( \ |
||||
|
queue_ ## type ## _node_t *); |
||||
|
|
||||
|
#endif /* QUEUE_FUNC_PROTO_H */ |
||||
@ -0,0 +1,241 @@ |
|||||
|
/** |
||||
|
* \file scot/queue_impl.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Templates of functions for handling queues based on typesafe lists. |
||||
|
* |
||||
|
* The Macros here generate the implementation for the interface to queues |
||||
|
* based on typesafe linked lists. |
||||
|
* \anchor onlyfunc_queue |
||||
|
* \attention |
||||
|
* All documentation here does document the functions that are created by |
||||
|
* the macros, as the macros themself are pretty easy and all used the same. |
||||
|
* They are called with a type, that MUST be one word (use typedef if needed) |
||||
|
* and generates the function defined with their value. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef QUEUE_IMPL_H |
||||
|
#define QUEUE_IMPL_H |
||||
|
|
||||
|
#include <scot/list.h> |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param type the datatype that this queue code should handle. |
||||
|
* \param a a variable holding a pointer to list_[type]_node_t. |
||||
|
* |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* a must be a valid pointer to a list_[type]_node_t. |
||||
|
* \returns \a a cast to a pointer of queue_[type]_node_t. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Cast a pointer to queue_[type]_node_t. |
||||
|
* |
||||
|
* FIXME: I should check better the validity of \a a. |
||||
|
*/ |
||||
|
#define QUEUE(type, a) (queue_ ## type ## _node_t *) (a) |
||||
|
|
||||
|
extern const char *queue_err_msg[]; |
||||
|
|
||||
|
|
||||
|
#ifdef GEN_LOCAL |
||||
|
# define STATIC static |
||||
|
#else |
||||
|
# define STATIC |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_queue "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \pre GEN_LIST_NEW(type) has to be called previously. |
||||
|
* \return NULL on error, but only if no exceptions are used. |
||||
|
* If exceptions are used an exception is thrown on error. |
||||
|
* On success a pointer to the newly created list_anchor |
||||
|
* will be returned. |
||||
|
* \retval NULL if an error occurs and no exceptions are used. |
||||
|
* \retval !=NULL the pointer to the newly created list anchor. |
||||
|
* \post enough memory on the heap. |
||||
|
* |
||||
|
* \brief template for queue constructor. |
||||
|
* |
||||
|
* this simply calls list_[type]_new(), that must be generated previously |
||||
|
* by a call of GEN_LIST_NEW(type). |
||||
|
*/ |
||||
|
#define GEN_QUEUE_NEW(type) \ |
||||
|
STATIC \ |
||||
|
queue_ ## type ## _node_t * \ |
||||
|
queue_ ## type ## _new (queue_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
return anchor = QUEUE (type, \ |
||||
|
list_ ## type ## _new (LIST (type, anchor))); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_queue "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \pre GEN_LIST_FREE(type) has to be called previously. |
||||
|
* \return Nothing |
||||
|
* \post The list is completely removed from the heap. |
||||
|
* |
||||
|
* \brief template for queue destructor. |
||||
|
* |
||||
|
* this simply calls list_[type]_free(), that must be generated previously |
||||
|
* by a call of GEN_LIST_FREE(type). |
||||
|
*/ |
||||
|
#define GEN_QUEUE_FREE(type) \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
queue_ ## type ## _free (queue_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _free (LIST (type, anchor)); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_queue "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \param e A pointer to a variable of the \a type, the |
||||
|
* list was created for. |
||||
|
* \pre GEN_LIST_LAST(type) and GEN_LIST_INSERT(type) |
||||
|
* has to be called previously. |
||||
|
* \return The inserted element \a e. |
||||
|
* \post Element \a e is enqueued in the queue pointed by |
||||
|
* \a anchor. |
||||
|
* |
||||
|
* \brief template for a function that enqueues a value into a queue. |
||||
|
* |
||||
|
* To add a value into a queue meens to put it at the end of the queue. |
||||
|
* That is done by getting the last node of the list and insert a value |
||||
|
* behind it. |
||||
|
*/ |
||||
|
#define GEN_QUEUE_ENQUEUE(type) \ |
||||
|
queue_ ## type ## _node_t * \ |
||||
|
queue_ ## type ## _enqueue ( \ |
||||
|
queue_ ## type ## _node_t *anchor, \ |
||||
|
const type *e) \ |
||||
|
{ \ |
||||
|
return QUEUE (type, list_ ## type ## _insert ( \ |
||||
|
list_ ## type ## _last (LIST (type, anchor)), e)); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_queue "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \pre GEN_LIST_NEXT(type), GEN_LIST_RETRIVE(type) |
||||
|
* GEN_LIST_ISEMPTY(type) and GEN_LIST_DELETE(type) |
||||
|
* has to be called previously. |
||||
|
* \return The dequeued element. |
||||
|
* \post One Element is dequeued from the queue pointed to |
||||
|
* by \a anchor. |
||||
|
* |
||||
|
* \brief template for a function that dequeues a value from a queue. |
||||
|
* |
||||
|
* Dequeue means get and remove the first element from the queue. |
||||
|
* This is done here. |
||||
|
*/ |
||||
|
#define GEN_QUEUE_DEQUEUE(type) \ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
queue_ ## type ## _dequeue (queue_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *next; \ |
||||
|
const type *e; \ |
||||
|
\ |
||||
|
next = list_ ## type ## _next (LIST (type, anchor)); \ |
||||
|
e = list_ ## type ## _retrive (next); \ |
||||
|
\ |
||||
|
if (! list_ ## type ## _isempty (next)) \ |
||||
|
list_ ## type ## _delete (next); \ |
||||
|
\ |
||||
|
return (type *) e; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_queue "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \pre GEN_LIST_NEXT(type) and GEN_LIST_RETRIVE(type) |
||||
|
* has to be called previously. |
||||
|
* \return The next element in the queue. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief get next element in the queue without dequeueing it. |
||||
|
*/ |
||||
|
#define GEN_QUEUE_TOP(type) \ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
queue_ ## type ## _top ( \ |
||||
|
queue_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
return list_ ## type ## _retrive ( \ |
||||
|
list_ ## type ## _next (LIST (type, anchor))); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST_IMPL(type) should be called before this. |
||||
|
* \return Nothing |
||||
|
* \post The functions, struct and globals to handle queues |
||||
|
* based on typesave |
||||
|
* lists for the given datatype are generated within the |
||||
|
* calling build file. |
||||
|
* |
||||
|
* \brief this creates all functions, structs and globals needed for a |
||||
|
* queue based on typesafe list of a given \a type. |
||||
|
* |
||||
|
* In detail the following is created by this macro:\n |
||||
|
* \li <b>struct queue_[type]_node_t</b>: This is the structure a queue |
||||
|
* is constructed of. Practically this just contains an instance of a |
||||
|
* list_[type]_node_t, as queues are completely based on lists and does |
||||
|
* not add further information. |
||||
|
* \li all functions created by the macros defined within this file. |
||||
|
*/ |
||||
|
#define GEN_QUEUE_IMPL(type) \ |
||||
|
struct queue_ ## type ## _node_t \ |
||||
|
{ \ |
||||
|
struct list_ ## type ## _node_t list; \ |
||||
|
}; \ |
||||
|
\ |
||||
|
GEN_QUEUE_NEW (type) \ |
||||
|
GEN_QUEUE_FREE (type) \ |
||||
|
GEN_QUEUE_ENQUEUE (type) \ |
||||
|
GEN_QUEUE_DEQUEUE (type) \ |
||||
|
GEN_QUEUE_TOP (type) |
||||
|
|
||||
|
#endif /* QUEUE_IMPL_H */ |
||||
@ -0,0 +1,68 @@ |
|||||
|
/** |
||||
|
* \file scot/queue_proto.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief This generates all prototypes needed for queues based on |
||||
|
* typesafe lists. |
||||
|
* |
||||
|
* This combines the macro definitions in \link scot/queue_type_proto.h |
||||
|
* scot/queue_type_proto.h \endlink and \link scot/queue_func_proto.h |
||||
|
* scot/queue_func_proto.h \endlink. |
||||
|
* Additionally defines for all errornumbers that queue will create can be |
||||
|
* found here. |
||||
|
* GEN_QUEUE_PROTO is normally called in a header file that describes a |
||||
|
* new Datatype and also wants lists of it. |
||||
|
* By doing this the complete interface to lists of that datatype is |
||||
|
* produced. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef QUEUE_PROTO_H |
||||
|
#define QUEUE_PROTO_H |
||||
|
|
||||
|
#include <scot/queue_type_proto.h> |
||||
|
#include <scot/queue_func_proto.h> |
||||
|
|
||||
|
/** |
||||
|
* \brief errnum if queue is empty |
||||
|
* \attention This is actually not use and will probably never be used |
||||
|
* in this form. |
||||
|
*/ |
||||
|
#define QUEUE_EMPTY 0 |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST_PROTO(type) should have been called previous |
||||
|
* to this call. |
||||
|
* \return Nothing |
||||
|
* \post The typedefs, struct declaration and function prototypes |
||||
|
* for functions to queues based on lists for the given |
||||
|
* datatype are generated within the calling build file. |
||||
|
* |
||||
|
* \brief this creates all typdefs, declarations and prototypes needed for a |
||||
|
* queue based on typesafe list of a given \a type. |
||||
|
* This is normally calles within a header file. |
||||
|
*/ |
||||
|
#define GEN_QUEUE_PROTO(type) \ |
||||
|
GEN_QUEUE_TYPE_PROTO (type) \ |
||||
|
GEN_QUEUE_FUNC_PROTO (type) |
||||
|
|
||||
|
#endif /* QUEUE_PROTO_H */ |
||||
@ -0,0 +1,61 @@ |
|||||
|
/** |
||||
|
* \file scot/queue_type_proto.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro that creates the datatype for handling queues based on |
||||
|
* linked lists. |
||||
|
* |
||||
|
* The macros here create all datatype prototypes and typedefs declarations to |
||||
|
* the implementations created by the macros in |
||||
|
* \link scot/queue_impl.h scot/queue_impl.h\endlink. |
||||
|
* These macros are normally not called directly within your code but |
||||
|
* through \link scot/queue_proto.h::GEN_QUEUE_PROTO GEN_QUEUE_PROTO\endlink. |
||||
|
* This is because normally one did not only |
||||
|
* want the datatypes but also the interface declaration to them. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef QUEUE_TYPE_PROTO_H |
||||
|
#define QUEUE_TYPE_PROTO_H |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST_TYPE_PROTO(type) should have been called |
||||
|
* previous to this. |
||||
|
* \return Nothing |
||||
|
* \post The datatype prototypes for queues based on lists |
||||
|
* of the given datatype are created. |
||||
|
* |
||||
|
* \brief Datatype prototypes to queues. |
||||
|
* |
||||
|
* This creates the prototypes of the datatypes needed to use the |
||||
|
* queue interface. |
||||
|
* |
||||
|
* Normally this is not called directly, but by |
||||
|
* \link scot/queue_proto.h::GEN_QUEUE_PROTO GEN_QUEUE_PROTO()\endlink |
||||
|
* because it is also neccesary to create the interface to this |
||||
|
* datatypes for working queues. |
||||
|
*/ |
||||
|
#define GEN_QUEUE_TYPE_PROTO(type) \ |
||||
|
struct queue_ ## type ## _node_t; \ |
||||
|
typedef struct queue_ ## type ## _node_t \ |
||||
|
queue_ ## type ## _node_t; |
||||
|
|
||||
|
#endif /* QUEUE_TYPE_PROTO_H */ |
||||
@ -0,0 +1,19 @@ |
|||||
|
#ifndef SCOT_EXCEPTIONS_H |
||||
|
#define SCOT_EXCEPTIONS_H |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
|
||||
|
#define MALLOC_ERR 0x00 |
||||
|
#define NULL_PTR_ERR 0x01 |
||||
|
|
||||
|
extern const char *scot_err_msg[]; |
||||
|
|
||||
|
void * exc_malloc (SIZE_T); |
||||
|
void * exc_malloc_fl (SIZE_T, const char *, int); |
||||
|
void check_null (const void *); |
||||
|
void check_null_fl (const void *, const char *, int); |
||||
|
|
||||
|
#endif /* SCOT_EXCEPTIONS_H */ |
||||
@ -0,0 +1,85 @@ |
|||||
|
#ifndef SCOT_SOCKET_H |
||||
|
#define SCOT_SOCKET_H |
||||
|
|
||||
|
#include <scot_common.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
#ifndef WIN32 |
||||
|
# include <netdb.h> |
||||
|
# include <sys/socket.h> |
||||
|
# include <sys/un.h> |
||||
|
# include <arpa/inet.h> |
||||
|
# include <netinet/in.h> |
||||
|
# include <stdlib.h> |
||||
|
# include <errno.h> |
||||
|
|
||||
|
# define INVALID_SOCKET -1 |
||||
|
# define SCOT_ERRNO errno |
||||
|
# define SCOT_H_ERRNO h_errno |
||||
|
# define SOCKET int |
||||
|
# define SCOT_SOCK_CLOSE close |
||||
|
#else |
||||
|
# include <winsock.h> |
||||
|
|
||||
|
# define SCOT_ERRNO WSAGetLastError() |
||||
|
# define SCOT_H_ERRNO WSAGetLastError() |
||||
|
# define SCOT_SOCK_CLOSE closesocket |
||||
|
#endif /* WIN32 */ |
||||
|
|
||||
|
#include <scot/stream.h> |
||||
|
|
||||
|
/* |
||||
|
* prevent direct access to the structure |
||||
|
* from other methods then the ones that are made for this. |
||||
|
* Should especially encourage the use of getter and setter |
||||
|
* functions |
||||
|
*/ |
||||
|
#ifndef USE_STRUCT_SCOT_SOCKET |
||||
|
struct scot_socket |
||||
|
{ |
||||
|
const char _ [sizeof (struct { |
||||
|
struct scot_stream socket; |
||||
|
struct sockaddr * sa; |
||||
|
SIZE_T addr_len; |
||||
|
})]; |
||||
|
}; |
||||
|
#else |
||||
|
struct scot_socket |
||||
|
{ |
||||
|
struct scot_stream socket; |
||||
|
struct sockaddr * sa; |
||||
|
SIZE_T addr_len; |
||||
|
}; |
||||
|
#endif /* USE_STRUCT_SCOT_SOCKET */ |
||||
|
|
||||
|
/* socket errors */ |
||||
|
#define SCOT_SOCKET_NEW_FAIL 0 |
||||
|
#define SCOT_SOCKET_LISTEN_FAIL 1 |
||||
|
#define SCOT_SOCKET_ACCEPT_FAIL 2 |
||||
|
#define SCOT_SOCKET_CONNECT_FAIL 3 |
||||
|
#define SCOT_SOCKET_NO_VALID_HOST 4 |
||||
|
#define SCOT_SOCKET_AF_NOT_IMPLEMENTED 5 |
||||
|
/* socket warnings */ |
||||
|
#define SCOT_SOCKET_UN_FILE_EXISTS 0 |
||||
|
extern const char * scot_socket_errmsg[]; |
||||
|
extern const char * scot_socket_wrnmsg[]; |
||||
|
|
||||
|
/* |
||||
|
* This function initializes scot sockets. This primary means it does |
||||
|
* nothing under a posix system an WSASartup on a Windows system. |
||||
|
*/ |
||||
|
void scot_socket_init (uint16_t, uint16_t); |
||||
|
/* |
||||
|
* This finalizes the scot sockets system. Again does noting on posix |
||||
|
* and WSACleanup on Windows. |
||||
|
*/ |
||||
|
void scot_socket_fini (void); |
||||
|
|
||||
|
void scot_socket_listen (const struct scot_socket*); |
||||
|
struct scot_socket * scot_socket_accept (const struct scot_socket*); |
||||
|
void scot_socket_connect (const struct scot_socket*, |
||||
|
const char *); |
||||
|
|
||||
|
void scot_socket_free (struct scot_socket*); |
||||
|
|
||||
|
#endif /* SCOT_SOCKET_H */ |
||||
@ -0,0 +1,15 @@ |
|||||
|
#ifndef SCOT_SOCKET_IN_H |
||||
|
#define SCOT_SOCKET_IN_H |
||||
|
|
||||
|
extern const char * scot_socket_errmsg[]; |
||||
|
|
||||
|
|
||||
|
struct scot_socket * scot_socket_in_new (const char*, const char*); |
||||
|
struct scot_socket * scot_socket_in_accept (const struct scot_socket*); |
||||
|
void scot_socket_in_prep_con (const struct scot_socket *, |
||||
|
const char *); |
||||
|
|
||||
|
const char * scot_socket_in_get_host (struct scot_socket *); |
||||
|
const char * scot_socket_in_get_ddc (struct scot_socket *); |
||||
|
|
||||
|
#endif /* SCOT_SOCKET_IN_H */ |
||||
@ -0,0 +1,14 @@ |
|||||
|
#ifndef SCOT_SOCKET_UN_H |
||||
|
#define SCOT_SOCKET_UN_H |
||||
|
|
||||
|
extern const char * scot_socket_errmsg[]; |
||||
|
|
||||
|
|
||||
|
struct scot_socket * scot_socket_un_new (const char*); |
||||
|
struct scot_socket * scot_socket_un_accept (const struct scot_socket*); |
||||
|
void scot_socket_un_prep_con (const struct scot_socket *, |
||||
|
const char *); |
||||
|
|
||||
|
const char * scot_socket_un_get_path (struct scot_socket*); |
||||
|
|
||||
|
#endif /* SCOT_SOCKET_UN_H */ |
||||
@ -0,0 +1,69 @@ |
|||||
|
/** |
||||
|
* \file scot/stack.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro which produce all prototypes and implementations for |
||||
|
* handling stacks based on linked lists by Templates. |
||||
|
* |
||||
|
* This is the toplevel template file for stacks based on typesafe lists. |
||||
|
* It is quite simple. It just defines one MACRO which in turn calls two |
||||
|
* other macros to generate all that is needed for queue-handling of a queue |
||||
|
* to a given type. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef STACK_H |
||||
|
#define STACK_H |
||||
|
|
||||
|
#include <scot/stack_proto.h> |
||||
|
#include <scot/stack_impl.h> |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST(type) has to be called for the list functions, |
||||
|
* as queues depend on these. |
||||
|
* \return Nothing |
||||
|
* \post The complete framework of functions, types, globals |
||||
|
* prototypes and definitions to handle stacks based on |
||||
|
* typesafe |
||||
|
* lists for the given datatype are generated within the |
||||
|
* calling build file. |
||||
|
* |
||||
|
* \brief create complete framework to handle stacks based on typesafe lists. |
||||
|
* |
||||
|
* This macro first colls GEN_STACK_PROTO() to create all prototypes |
||||
|
* neccesary for handling stacks of the given \a type. And then it calls |
||||
|
* GEN_STACK_IMPL() to also create the neccesary definitions and |
||||
|
* implementations.\ |
||||
|
* Normally this macro is only called if one only wants to have stacks |
||||
|
* of the given type in a single c source file and nowhere else. Normally |
||||
|
* this is then used in conjunction with a previous define of GEN_LOCAL, |
||||
|
* that tells GEN_STACK() and the subsequent macros to generate the functions |
||||
|
* as static.\n |
||||
|
* If one wants to used queues of the given type in several places of the |
||||
|
* project one would normally call GEN_STACK_PROTO() in a h file and |
||||
|
* GEN_STACK_IMPL() in the c file that does the implementation of that |
||||
|
* h file (without GEN_LOCAL). |
||||
|
*/ |
||||
|
#define GEN_STACK(type) \ |
||||
|
GEN_STACK_PROTO (type) \ |
||||
|
GEN_STACK_IMPL (type) |
||||
|
|
||||
|
#endif /* STACK_H */ |
||||
@ -0,0 +1,89 @@ |
|||||
|
/** |
||||
|
* \file scot/stack_func_proto.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro that produces function prototypes for handling stacks |
||||
|
* based on linked lists. |
||||
|
* |
||||
|
* The macros here create all function prototypes to |
||||
|
* the implementations created by the macros in |
||||
|
* \link scot/stack_impl.h scot/stack_impl.h\endlink. |
||||
|
* These macros are normally not called directly within your code but |
||||
|
* through \link scot/stack_proto.h::GEN_STACK_PROTO GEN_STACK_PROTO\endlink. |
||||
|
* This is because to use the interface declaration |
||||
|
* provided here one will also need the typedefs and datatype prototypes. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef STACK_FUNC_PROTO_H |
||||
|
#define STACK_FUNC_PROTO_H |
||||
|
|
||||
|
|
||||
|
#ifdef GEN_LOCAL |
||||
|
# define STATIC static |
||||
|
#else |
||||
|
# define STATIC |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST_FUNC_PROTO should have bin called previously |
||||
|
* in one or the other way. |
||||
|
* \return Nothing |
||||
|
* \post All function prototypes for a stack of the given |
||||
|
* datatype are created. |
||||
|
* |
||||
|
* \brief This creates the prototypes to all stack functions |
||||
|
* |
||||
|
* This creates all the prototypes to the functions that are created by |
||||
|
* \link scot/stack_impl.h::GEN_STACK_IMPL GEN_STACK_IMPL\endlink in |
||||
|
* \link scot/stack_impl.h scot/stack_impl.h\endlink. |
||||
|
* This provides one with the complete interface to the stack of the given |
||||
|
* datatype. |
||||
|
*/ |
||||
|
#define GEN_STACK_FUNC_PROTO(type) \ |
||||
|
STATIC \ |
||||
|
stack_ ## type ## _node_t * \ |
||||
|
stack_ ## type ## _new ( \ |
||||
|
stack_ ## type ## _node_t *); \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
stack_ ## type ## _free ( \ |
||||
|
stack_ ## type ## _node_t *); \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
stack_ ## type ## _node_t * \ |
||||
|
stack_ ## type ## _push ( \ |
||||
|
stack_ ## type ## _node_t *, \ |
||||
|
const type *); \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
stack_ ## type ## _pop ( \ |
||||
|
stack_ ## type ## _node_t *); \ |
||||
|
\ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
stack_ ## type ## _top ( \ |
||||
|
stack_ ## type ## _node_t *); |
||||
|
|
||||
|
#endif /* STACK_FUNC_PROTO_H */ |
||||
@ -0,0 +1,239 @@ |
|||||
|
/** |
||||
|
* \file scot/stack_impl.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Templates of functions for handling stacks based on typesafe lists. |
||||
|
* |
||||
|
* The Macros here generate the implementation for the interface to stacks |
||||
|
* based on typesafe linked lists. |
||||
|
* \anchor onlyfunc_stack |
||||
|
* \attention |
||||
|
* All documentation here does document the functions that are created by |
||||
|
* the macros, as the macros themself are pretty easy and all used the same. |
||||
|
* They are called with a type, that MUST be one word (use typedef if needed) |
||||
|
* and generates the function defined with their value. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef STACK_IMPL_H |
||||
|
#define STACK_IMPL_H |
||||
|
|
||||
|
#include <scot/list.h> |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param type the datatype that this queue code should handle. |
||||
|
* \param a a variable holding a pointer to list_[type]_node_t. |
||||
|
* |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* a must be a valid pointer to a list_[type]_node_t. |
||||
|
* \returns \a a cast to a pointer of stack_[type]_node_t. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Cast a pointer to stack_[type]_node_t. |
||||
|
* |
||||
|
* FIXME: I should check better the validity of \a a. |
||||
|
*/ |
||||
|
#define STACK(type, a) (stack_ ## type ## _node_t *) (a) |
||||
|
|
||||
|
extern const char *stack_err_msg[]; |
||||
|
|
||||
|
|
||||
|
#ifdef GEN_LOCAL |
||||
|
# define STATIC static |
||||
|
#else |
||||
|
# define STATIC |
||||
|
#endif |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_stack "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \pre GEN_LIST_NEW(type) has to be called previously. |
||||
|
* \return NULL on error, but only if no exceptions are used. |
||||
|
* If exceptions are used an exception is thrown on error. |
||||
|
* On success a pointer to the newly created list_anchor |
||||
|
* will be returned. |
||||
|
* \retval NULL if an error occurs and no exceptions are used. |
||||
|
* \retval !=NULL the pointer to the newly created list anchor. |
||||
|
* \post enough memory on the heap. |
||||
|
* |
||||
|
* \brief template for stack constructor. |
||||
|
* |
||||
|
* this simply calls list_[type]_new(), that must be generated previously |
||||
|
* by a call of GEN_LIST_NEW(type). |
||||
|
*/ |
||||
|
#define GEN_STACK_NEW(type) \ |
||||
|
STATIC \ |
||||
|
stack_ ## type ## _node_t * \ |
||||
|
stack_ ## type ## _new (stack_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
return anchor = STACK (type, \ |
||||
|
list_ ## type ## _new (LIST (type, anchor))); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_stack "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \pre GEN_LIST_FREE(type) has to be called previously. |
||||
|
* \return Nothing |
||||
|
* \post The list is completely removed from the heap. |
||||
|
* |
||||
|
* \brief template for stack destructor. |
||||
|
* |
||||
|
* this simply calls list_[type]_free(), that must be generated previously |
||||
|
* by a call of GEN_LIST_FREE(type). |
||||
|
*/ |
||||
|
#define GEN_STACK_FREE(type) \ |
||||
|
STATIC \ |
||||
|
void \ |
||||
|
stack_ ## type ## _free (stack_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _free (LIST (type, anchor)); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_stack "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \param e A pointer to a variable of the \a type, the |
||||
|
* list was created for. |
||||
|
* \pre GEN_LIST_INSERT(type) has to be called previously. |
||||
|
* \return The pushed element \a e. |
||||
|
* \post Element \a e is pushed in the stack pointed by |
||||
|
* \a anchor. |
||||
|
* |
||||
|
* \brief template for a function that pushes a value into a stack. |
||||
|
* |
||||
|
* To add a value into a stack meens to put it at the beginning of the stack. |
||||
|
* That is simply a call to list_[type]_insert(). |
||||
|
*/ |
||||
|
#define GEN_STACK_PUSH(type) \ |
||||
|
STATIC \ |
||||
|
stack_ ## type ## _node_t * \ |
||||
|
stack_ ## type ## _push ( \ |
||||
|
stack_ ## type ## _node_t *anchor, \ |
||||
|
const type *e) \ |
||||
|
{ \ |
||||
|
return STACK (type, list_ ## type ## _insert ( \ |
||||
|
LIST (type, anchor), e)); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_stack "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \pre GEN_LIST_NEXT(type), GEN_LIST_RETRIVE(type) |
||||
|
* GEN_LIST_ISEMPTY(type) and GEN_LIST_DELETE(type) |
||||
|
* has to be called previously. |
||||
|
* \return The poped element. |
||||
|
* \post One Element is poped from the stack pointed to |
||||
|
* by \a anchor. |
||||
|
* |
||||
|
* \brief template for a function that pops a value from a stack. |
||||
|
* |
||||
|
* Pop means get and remove the first element from the stack. |
||||
|
* This is done here. |
||||
|
*/ |
||||
|
#define GEN_STACK_POP(type) \ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
stack_ ## type ## _pop (stack_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
list_ ## type ## _node_t *next; \ |
||||
|
const type *e; \ |
||||
|
\ |
||||
|
next = list_ ## type ## _next (LIST (type, anchor)); \ |
||||
|
e = list_ ## type ## _retrive (next); \ |
||||
|
\ |
||||
|
if (! list_ ## type ## _isempty (next)) \ |
||||
|
list_ ## type ## _delete (next); \ |
||||
|
\ |
||||
|
return (type *) e; \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \attention |
||||
|
* Only the generated function is explained here, for the reason look |
||||
|
* \ref onlyfunc_stack "here". |
||||
|
* |
||||
|
* \param anchor a pointer that should contain the list anchor. |
||||
|
* \pre GEN_LIST_NEXT(type) and GEN_LIST_RETRIVE(type) |
||||
|
* has to be called previously. |
||||
|
* \return The next element in the stack. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief get next element in the stack without poping it. |
||||
|
*/ |
||||
|
#define GEN_STACK_TOP(type) \ |
||||
|
STATIC \ |
||||
|
type * \ |
||||
|
stack_ ## type ## _top ( \ |
||||
|
stack_ ## type ## _node_t *anchor) \ |
||||
|
{ \ |
||||
|
return list_ ## type ## _retrive ( \ |
||||
|
list_ ## type ## _next (LIST (type, anchor))); \ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST_IMPL(type) should be called before this. |
||||
|
* \return Nothing |
||||
|
* \post The functions, struct and globals to handle stacks |
||||
|
* based on typesave |
||||
|
* lists for the given datatype are generated within the |
||||
|
* calling build file. |
||||
|
* |
||||
|
* \brief this creates all functions, structs and globals needed for a |
||||
|
* stack based on typesafe list of a given \a type. |
||||
|
* |
||||
|
* In detail the following is created by this macro:\n |
||||
|
* \li <b>struct stack_[type]_node_t</b>: This is the structure a stack |
||||
|
* is constructed of. Practically this just contains an instance of a |
||||
|
* list_[type]_node_t, as stacks are completely based on lists and does |
||||
|
* not add further information. |
||||
|
* \li all functions created by the macros defined within this file. |
||||
|
*/ |
||||
|
#define GEN_STACK_IMPL(type) \ |
||||
|
struct stack_ ## type ## _node_t \ |
||||
|
{ \ |
||||
|
struct list_node_t list; \ |
||||
|
}; \ |
||||
|
\ |
||||
|
GEN_STACK_NEW (type) \ |
||||
|
GEN_STACK_FREE (type) \ |
||||
|
GEN_STACK_PUSH (type) \ |
||||
|
GEN_STACK_POP (type) \ |
||||
|
GEN_STACK_TOP (type) |
||||
|
|
||||
|
#endif /* STACK_IMPL_H */ |
||||
@ -0,0 +1,68 @@ |
|||||
|
/** |
||||
|
* \file scot/stack_proto.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief This generates all prototypes needed for stacks based on |
||||
|
* typesafe lists. |
||||
|
* |
||||
|
* This combines the macro definitions in \link scot/stack_type_proto.h |
||||
|
* scot/stack_type_proto.h \endlink and \link scot/stack_func_proto.h |
||||
|
* scot/stack_func_proto.h \endlink. |
||||
|
* Additionally defines for all errornumbers that stack will create can be |
||||
|
* found here. |
||||
|
* GEN_STACK_PROTO is normally called in a header file that describes a |
||||
|
* new Datatype and also wants lists of it. |
||||
|
* By doing this the complete interface to lists of that datatype is |
||||
|
* produced. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef STACK_PROTO_H |
||||
|
#define STACK_PROTO_H |
||||
|
|
||||
|
#include <scot/stack_type_proto.h> |
||||
|
#include <scot/stack_func_proto.h> |
||||
|
|
||||
|
/** |
||||
|
* \brief errnum if stack is empty |
||||
|
* \attention This is actually not use and will probably never be used |
||||
|
* in this form. |
||||
|
*/ |
||||
|
#define STACK_EMPTY 0 |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST_PROTO(type) should have been called previous |
||||
|
* to this call. |
||||
|
* \return Nothing |
||||
|
* \post The typedefs, struct declaration and function prototypes |
||||
|
* for functions to stacks based on lists for the given |
||||
|
* datatype are generated within the calling build file. |
||||
|
* |
||||
|
* \brief this creates all typdefs, declarations and prototypes needed for a |
||||
|
* stack based on typesafe list of a given \a type. |
||||
|
* This is normally calles within a header file. |
||||
|
*/ |
||||
|
#define GEN_STACK_PROTO(type) \ |
||||
|
GEN_STACK_TYPE_PROTO (type) \ |
||||
|
GEN_STACK_FUNC_PROTO (type) |
||||
|
|
||||
|
#endif /* STACK_PROTO_H */ |
||||
@ -0,0 +1,61 @@ |
|||||
|
/** |
||||
|
* \file scot/stack_type_proto.h |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Macro that creates the datatype for handling stacks based on |
||||
|
* linked lists. |
||||
|
* |
||||
|
* The macros here create all datatype prototypes and typedefs declarations to |
||||
|
* the implementations created by the macros in |
||||
|
* \link scot/stack_impl.h scot/stack_impl.h\endlink. |
||||
|
* These macros are normally not called directly within your code but |
||||
|
* through \link scot/stack_proto.h::GEN_STACK_PROTO GEN_STACK_PROTO\endlink. |
||||
|
* This is because normally one did not only |
||||
|
* want the datatypes but also the interface declaration to them. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#ifndef STACK_TYPE_PROTO_H |
||||
|
#define STACK_TYPE_PROTO_H |
||||
|
|
||||
|
/** |
||||
|
* \param type the datatype that this list code should handle. |
||||
|
* \pre Type must be a single word typename. If one wants |
||||
|
* to use e.g. lists of structs one has to use typedef |
||||
|
* to create a single word type name like this: |
||||
|
* typedef struct mystruct_t mystruct_t; |
||||
|
* GEN_LIST_TYPE_PROTO(type) should have been called |
||||
|
* previous to this. |
||||
|
* \return Nothing |
||||
|
* \post The datatype prototypes for stacks based on lists |
||||
|
* of the given datatype are created. |
||||
|
* |
||||
|
* \brief Datatype prototypes to stacks. |
||||
|
* |
||||
|
* This creates the prototypes of the datatypes needed to use the |
||||
|
* stack interface. |
||||
|
* |
||||
|
* Normally this is not called directly, but by |
||||
|
* \link scot/stack_proto.h::GEN_STACK_PROTO GEN_STACK_PROTO()\endlink |
||||
|
* because it is also neccesary to create the interface to this |
||||
|
* datatypes for working stacks. |
||||
|
*/ |
||||
|
#define GEN_STACK_TYPE_PROTO(type) \ |
||||
|
struct stack_ ## type ## _node_t; \ |
||||
|
typedef struct stack_ ## type ## _node_t \ |
||||
|
stack_ ## type ## _node_t; \ |
||||
|
|
||||
|
#endif /* STACK_TYPE_PROTO_H */ |
||||
@ -0,0 +1,132 @@ |
|||||
|
/* |
||||
|
* Zunächst ein paar allgemeine Bemerkungen zu scot_stream: |
||||
|
* |
||||
|
* 1. scot-stream ist eine auf andere Klassen aufbauende Klasse. Es gibt |
||||
|
* kein scot_stream_new. Mann kann natürlich über malloc ein leeres |
||||
|
* stream-objekt anlegen, das macht für gewöhnlich aber keinen Sinn. |
||||
|
* Stattdessen gibt es in Klassen, die stream-io Endpunkte darstellen |
||||
|
* Funktionen der Form scot_<Klasse>_get_new_stream |
||||
|
* (z.B. scot_socket_get_new_stream). Diese Funktionen geben ein |
||||
|
* gültiges Stream Objekt zu einem Objekt der übergeordneten Klasse |
||||
|
* zurück. Das Objekt der übergeordnete Klasse muss sich alle auf diese |
||||
|
* Art angelegten Stream-Objekte merken. |
||||
|
* 2. Wenn ein Objekt der übergeordneten Klasse geschlossen wird, so werden |
||||
|
* auch alle Stream Objekte die von diesem erzeugt wurden freigegeben und |
||||
|
* auf NULL gesetzt. (Auf Sie währe eh keine Sinnvolle operation mehr |
||||
|
* möglich.) |
||||
|
* 3. Wird ein Stream-Objekt freigegeben, so bleibt das übergeordnete |
||||
|
* Objekt erhalten (und somit auch der handle geöffnet). |
||||
|
* 4. Ein close auf ein Stream Objekt schließt auch das übergeordnete |
||||
|
* Objekt und gibt es frei. Somit werden auch alle weiteren Stream |
||||
|
* Objekte geschlossen. |
||||
|
* |
||||
|
* !!!Zusammenfassend bleibt nochmal hervorzuheben das close gegenüber free |
||||
|
* die stärkere operation ist und zu einem free aller stream objekte und |
||||
|
* des übergeordneten Objekts führt.!!! |
||||
|
*/ |
||||
|
#ifndef SCOT_STREAM_H |
||||
|
#define SCOT_STREAM_H |
||||
|
|
||||
|
#include <scot/scot_int.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
#define SCOT_STREAM_BUF_SIZE 100 |
||||
|
|
||||
|
/* scot stream types (scot_stream:s_type) . */ |
||||
|
/* Die ersten bis zum --- Kommentar sind stream_pool fähig */ |
||||
|
#define SCOT_STREAM_TYPE_SOCKET 0 |
||||
|
#define SCOT_STREAM_TYPE_PIPE 1 |
||||
|
#define SCOT_STREAM_TYPE_TERM 2 |
||||
|
/* --- */ |
||||
|
#define SCOT_STREAM_TYPE_FILE 3 |
||||
|
#define SCOT_STREAM_TYPE_INOTIFY 4 |
||||
|
|
||||
|
#ifdef WIN32 |
||||
|
# include <Windows.h> |
||||
|
# include <scot/stream_win.h> |
||||
|
# define SCOT_FILE_READ win_file_read |
||||
|
#else |
||||
|
# define SCOT_FILE_READ read |
||||
|
#endif /* WIN32 */ |
||||
|
|
||||
|
/* s must me a pointer to a stream...this is normally the case! */ |
||||
|
#define SCOT_STREAM_TO_SOCKET(s) ((struct scot_socket *)(s)) |
||||
|
#define SCOT_STREAM_TO_PIPE(s) ((struct scot_pipe *)(s)) |
||||
|
#define SCOT_STREAM_TO_TERM(s) ((struct scot_term *)(s)) |
||||
|
#define SCOT_STREAM_TO_FILE(s) ((struct scot_file *)(s)) |
||||
|
#define SCOT_STREAM_TO_INOTIFY(s) ((struct scot_inotify *)(s)) |
||||
|
|
||||
|
/* |
||||
|
* get the base object of the given stream with the correct type |
||||
|
* Those base types has to be specified here at the moment... maybe |
||||
|
* sometimes there will be some kind of registration method for |
||||
|
* base types |
||||
|
*/ |
||||
|
#define SCOT_STREAM_PROV(st) \ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_SOCKET)? SCOT_STREAM_TO_SOCKET((st)):\ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_PIPE)? SCOT_STREAM_TO_PIPE((st)):\ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_TERM)? SCOT_STREAM_TO_TERM((st)):\ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_FILE)? SCOT_STREAM_TO_FILE((st)):\ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_INOTIFY)?SCOT_STREAM_TO_INOTIFY((st)):(st) |
||||
|
|
||||
|
#define SCOT_STREAM_FREE(st) \ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_SOCKET)?\ |
||||
|
scot_socket_free (SCOT_STREAM_TO_SOCKET (st)):\ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_PIPE)? scot_stream_free ((st)):\ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_TERM)? scot_stream_free ((st)):\ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_FILE)? scot_stream_free ((st)):\ |
||||
|
((st)->s_type == SCOT_STREAM_TYPE_INOTIFY)?scot_stream_free ((st)):\ |
||||
|
scot_stream_free ((st)) |
||||
|
|
||||
|
/* |
||||
|
* connections via ssl must be handled separately, because communication |
||||
|
* over them has some very distinc behaviour then with other streams. |
||||
|
* First, read and write are not done on a handle but on an ssl object. |
||||
|
* Next, ssl has an all or nothing approach. If a write could not send |
||||
|
* all data it sould be assumed as failed. This is neccessary for the |
||||
|
* encryption. |
||||
|
* Next, ssl is designed to sit on top of most stream types. Thus it |
||||
|
* is a separate object, that should be createable by a stream object. |
||||
|
*/ |
||||
|
|
||||
|
struct scot_stream |
||||
|
{ |
||||
|
#ifndef WIN32 |
||||
|
union |
||||
|
{ |
||||
|
int32_t file; |
||||
|
int32_t sock; |
||||
|
} handle; |
||||
|
#else |
||||
|
union |
||||
|
{ |
||||
|
HANDLE file; |
||||
|
SOCKET sock; |
||||
|
} handle; |
||||
|
#endif |
||||
|
char rbuf [SCOT_STREAM_BUF_SIZE]; |
||||
|
char wbuf [SCOT_STREAM_BUF_SIZE]; |
||||
|
uint32_t rbuf_idx; |
||||
|
uint32_t wbuf_idx; |
||||
|
int32_t s_type; /* an identifier of this stream (file, socket, pipe...) */ |
||||
|
int16_t s_blk; |
||||
|
}; |
||||
|
|
||||
|
int scot_stream_eof (struct scot_stream *); |
||||
|
SSIZE_T scot_stream_read (struct scot_stream *, char *, SIZE_T); |
||||
|
SSIZE_T scot_stream_write (struct scot_stream *, char *, SIZE_T); |
||||
|
void scot_stream_flush (struct scot_stream *); |
||||
|
|
||||
|
SSIZE_T scot_stream_read_pending (struct scot_stream *); |
||||
|
SSIZE_T scot_stream_write_pending (struct scot_stream *); |
||||
|
|
||||
|
int scot_stream_get_blocking (struct scot_stream *); |
||||
|
void scot_stream_set_block (struct scot_stream *); |
||||
|
void scot_stream_set_nonblock (struct scot_stream *); |
||||
|
|
||||
|
void scot_stream_close (struct scot_stream *); |
||||
|
int scot_stream_is_closed (struct scot_stream *); |
||||
|
|
||||
|
void scot_stream_free (struct scot_stream *); |
||||
|
|
||||
|
#endif /* SCOT_STREAM_H */ |
||||
@ -0,0 +1,72 @@ |
|||||
|
#ifndef SCOT_STREAM_POOL_H |
||||
|
#define SCOT_STREAM_POOL_H |
||||
|
|
||||
|
#include <sys/time.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <unistd.h> |
||||
|
|
||||
|
#include <scot/event_listener.h> |
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/thread.h> |
||||
|
#include <scot/stream_pool_fraction.h> |
||||
|
|
||||
|
#define GEN_LOCAL |
||||
|
# include <scot/list.h> |
||||
|
#undef GEN_LOCAL |
||||
|
|
||||
|
/* |
||||
|
* folgende masken dienen dazu zu bestimmen in welches fd_set |
||||
|
* (read, write, exception) ein filehandle eingetragen werden soll. |
||||
|
* D.h. für welche operation der select diesen handle überwachen soll. |
||||
|
*/ |
||||
|
#define SCOT_STREAM_POOL_FD_ADD_RMASK 0x1 |
||||
|
#define SCOT_STREAM_POOL_FD_ADD_WMASK 0x2 |
||||
|
#define SCOT_STREAM_POOL_FD_ADD_EMASK 0x4 |
||||
|
|
||||
|
#define SCOT_STREAM_POOL_CLEANUP 0x00 |
||||
|
#define SCOT_STREAM_POOL_RESTART_FRACTION 0x01 |
||||
|
#define SCOT_STREAM_POOL_START_FRACTION 0x02 |
||||
|
#define SCOT_STREAM_POOL_STOP_FRACTION 0x03 |
||||
|
#define SCOT_STREAM_POOL_RESTART_ALL_FRAC 0x04 |
||||
|
#define SCOT_STREAM_POOL_START_ALL_FRAC 0x05 |
||||
|
#define SCOT_STREAM_POOL_STOP_ALL_FRAC 0x06 |
||||
|
|
||||
|
#define SCOT_STREAM_POOL_KEEP_STREAMS 0x0 |
||||
|
#define SCOT_STREAM_POOL_FREE_STREAMS 0x1 |
||||
|
|
||||
|
|
||||
|
typedef struct scot_sp_fraction scot_sp_fraction; |
||||
|
GEN_LIST_TYPE_PROTO (scot_sp_fraction); |
||||
|
|
||||
|
struct scot_stream_pool |
||||
|
{ |
||||
|
struct scot_event_listener el; |
||||
|
|
||||
|
uint16_t cmd; |
||||
|
void * cmd_arg; |
||||
|
THREAD_COND_T cmd_cond; |
||||
|
THREAD_COND_CS_T cmd_cs; |
||||
|
|
||||
|
list_scot_sp_fraction_node_t * pool; |
||||
|
THREAD_MUTEX_T mutex; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
struct scot_stream_pool * scot_stream_pool_new (struct scot_stream_pool *); |
||||
|
void scot_stream_pool_free (struct scot_stream_pool *); |
||||
|
void scot_stream_pool_free_s (struct scot_stream_pool *, |
||||
|
int); |
||||
|
void scot_stream_pool_add (struct scot_stream_pool *, |
||||
|
struct scot_stream *, |
||||
|
int); |
||||
|
void scot_stream_pool_remove (struct scot_stream_pool *, |
||||
|
struct scot_stream *, |
||||
|
int); |
||||
|
int scot_stream_pool_get_rwe (struct scot_stream_pool *, |
||||
|
struct scot_stream *); |
||||
|
void scot_stream_pool_cmd (struct scot_stream_pool *, |
||||
|
uint16_t, |
||||
|
void *); |
||||
|
struct scot_stream * scot_sp_get_all_streams (struct scot_stream_pool *); |
||||
|
|
||||
|
#endif /* SCOT_STREAM_POOL_H */ |
||||
@ -0,0 +1,53 @@ |
|||||
|
#ifndef SCOT_STREAM_POOL_FRACTION_H |
||||
|
#define SCOT_STREAM_POOL_FRACTION_H |
||||
|
|
||||
|
#include <sys/time.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <unistd.h> |
||||
|
|
||||
|
#include <scot/stream_pool.h> |
||||
|
#include <scot/event_listener.h> |
||||
|
#include <scot/scot_int.h> |
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/thread.h> |
||||
|
|
||||
|
#define SCOT_MAX_FRACTION 64 /* Windows kann max. 64 Objekte pro thread |
||||
|
überwachen. */ |
||||
|
|
||||
|
struct scot_sp_fraction |
||||
|
{ |
||||
|
struct scot_event_listener * el; |
||||
|
|
||||
|
int stream_type; /* what streams to accept */ |
||||
|
|
||||
|
THREAD_T thread_handle; |
||||
|
THREAD_ID_T thread_id; |
||||
|
int thread_run_flg; |
||||
|
|
||||
|
scot_thread_entry_fptr spf_entry_func; |
||||
|
|
||||
|
uint16_t s_count; |
||||
|
struct scot_stream * s_list [SCOT_MAX_FRACTION]; |
||||
|
int free_s; |
||||
|
|
||||
|
/* for select */ |
||||
|
fd_set rfds, wfds, efds; |
||||
|
int max_fd; |
||||
|
}; |
||||
|
|
||||
|
extern scot_thread_entry_fptr scot_spf_thread_func[]; |
||||
|
|
||||
|
struct scot_sp_fraction * scot_spf_new (struct scot_sp_fraction *, |
||||
|
struct scot_event_listener *, |
||||
|
int); |
||||
|
void scot_spf_free (struct scot_sp_fraction *); |
||||
|
void scot_spf_free_s (struct scot_sp_fraction *, |
||||
|
int); |
||||
|
void scot_spf_add (struct scot_sp_fraction *, |
||||
|
struct scot_stream *, |
||||
|
int); |
||||
|
void scot_spf_remove (struct scot_sp_fraction *, |
||||
|
struct scot_stream *, |
||||
|
int); |
||||
|
|
||||
|
#endif /* SCOT_STREAM_POOL_FRACTION_H */ |
||||
@ -0,0 +1,8 @@ |
|||||
|
#ifndef SCOT_STREAM_WIN_H |
||||
|
#define SCOT_STREAM_WIN_H |
||||
|
|
||||
|
#include <windows.h> |
||||
|
|
||||
|
SSIZE_T win_file_read (HANDLE, void *, SIZE_T); |
||||
|
|
||||
|
#endif /* SCOT_STREAM_WIN_H */ |
||||
@ -0,0 +1,51 @@ |
|||||
|
/* |
||||
|
* used for threadsafety within exception |
||||
|
* actually only pthread is supported |
||||
|
*/ |
||||
|
#ifndef THREAD_H |
||||
|
#define THREAD_H |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
|
||||
|
#define JOIN_OK 0x00 |
||||
|
#define JOIN_TIMEOUT 0x01 |
||||
|
#define JOIN_ERROR 0x02 |
||||
|
|
||||
|
/* |
||||
|
* i guess it is possible to write mutex code that uses cond |
||||
|
* elements to timeout on lock, but right now i have no clear |
||||
|
* idea of how to do this. The following thoughts i had: |
||||
|
* - create a struct that holds a pthread_mutex_t and a pthread_cond_t |
||||
|
* for every mutex. |
||||
|
* - lock mutexes only by calling pthread_cond_timedwait |
||||
|
* And here starts the problem...to do a cond_timedwait i need to ensure |
||||
|
* that the mutex is already locked...well and then a question i have not |
||||
|
* clearyfied, if a thread ends, will all locks on mutexes be removed? |
||||
|
* I guess so, but i did not test it. And an even more important question, |
||||
|
* is it possible to write cleanup-code that guarantees that a |
||||
|
* pthread_cond_signal is called for every mutex the thread holds... |
||||
|
* well, we will end up with the requirement that the programmer has to |
||||
|
* call a release mutex function before ending a thread and if the programmer |
||||
|
* forgets that the behaviour of out code is unspecified |
||||
|
* Right now i will not support timeouts on mutex-locks and to be consistent |
||||
|
* it is not supported on win32 either, also it would be much easier to |
||||
|
* implement there. |
||||
|
*/ |
||||
|
#define MUTEX_LOCK_OK 0x00 |
||||
|
#define MUTEX_LOCK_ERROR 0x02 |
||||
|
|
||||
|
#define THREAD_T int |
||||
|
#define THREAD_ID_T int |
||||
|
#define THREAD_ID 0 |
||||
|
#define SELF_THREAD 0 |
||||
|
#define NEW_THREAD perror ("No supported thread system used!\n") |
||||
|
#define CANCEL_THREAD(t) NEW_THREAD |
||||
|
#define EXIT_THREAD(r) NEW_THREAD |
||||
|
#define JOIN_THREAD(t,i) NEW_THREAD |
||||
|
#define THREAD_CANCEL_ENABLE NEW_THREAD |
||||
|
#define THREAD_CANCEL_DISABLE NEW_THREAD |
||||
|
#define THREAD_CANCEL_ASYNC NEW_THREAD |
||||
|
#define THREAD_CANCEL_DEFER NEW_THREAD |
||||
|
#define T_PROC_RET int |
||||
|
|
||||
|
#endif /* THREAD_H */ |
||||
@ -0,0 +1,44 @@ |
|||||
|
/* |
||||
|
* dir.h: as one might suggest here are definitions and prototypes for |
||||
|
* win32/dir.c |
||||
|
* |
||||
|
* Copyright (C) 2006 Georg Steffers |
||||
|
* |
||||
|
* Author: Georg Steffers [GST] <georg.steffers@aschendorff.de> |
||||
|
* Developer: |
||||
|
* |
||||
|
* Changes (for this file only): |
||||
|
* (2006-06-12) [GST] Started this changelog...well the program is |
||||
|
* ready since some weeks right now. |
||||
|
*/ |
||||
|
#ifndef DIR_H |
||||
|
#define DIR_H |
||||
|
|
||||
|
#include <windows.h> |
||||
|
|
||||
|
#include <scot/dir_common.h> |
||||
|
|
||||
|
/* abstraction for file information and an directory handle */ |
||||
|
#define FILE_DATA struct dir_file |
||||
|
#define DIR_HANDLE HANDLE |
||||
|
|
||||
|
/* abstraction for checking if a file is a directory */ |
||||
|
#define IS_DIRECTORY(file_data) \ |
||||
|
((file_data).file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
||||
|
|
||||
|
/* abstraction for getting the filename of a directory entry. */ |
||||
|
#define DIRENT_FNAME(file_data) ((file_data).file.cFileName) |
||||
|
|
||||
|
/* structure for all available information about the directory entry. */ |
||||
|
struct dir_file |
||||
|
{ |
||||
|
char path [MAX_PATH+1]; |
||||
|
WIN32_FIND_DATA file; |
||||
|
}; |
||||
|
|
||||
|
/* the last in parameter is posix specific. It defines if stat should |
||||
|
* follow symlinks or not. Under Windows it is ignored. */ |
||||
|
DIR_HANDLE get_dir_first (const char *, FILE_DATA *, int); |
||||
|
int get_dir_next (DIR_HANDLE, const char *, FILE_DATA *, int); |
||||
|
|
||||
|
#endif /* DIR_H */ |
||||
@ -0,0 +1,40 @@ |
|||||
|
/*************************************************************************** |
||||
|
* memory.h: Prototypes for default memory operations like memcpy and thus * |
||||
|
* on a win32 system nearly all CRT functions (CRT is the * |
||||
|
* windows C RunTime, that is the normal libC) aren't thread- * |
||||
|
* safe. As i build up tests this causes problems for example * |
||||
|
* with strcpy. So i decided to write wrapper that use non CRT * |
||||
|
* functions on Windows and normal libC ones on a posix system. * |
||||
|
* * |
||||
|
* Author: Georg Steffers <georg@steffers.org> * |
||||
|
* Date: 03/06/2006 * |
||||
|
***************************************************************************/ |
||||
|
#ifndef MEMORY_H |
||||
|
#define MEMORY_H |
||||
|
|
||||
|
#include <windows.h> |
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
#include <scot_common.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
#define SCOT_MEM_GET(s) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (s)); |
||||
|
#define SCOT_MEM_FREE(p) \ |
||||
|
if ((p)) {HeapFree(GetProcessHeap(), 0, (p)); (p)=NULL;} |
||||
|
#define SCOT_MEM_COPY(p,q,s) (CopyMemory ((p), (q), (s)), (p)) |
||||
|
#define SCOT_MEM_MOVE(p,q,s) (MoveMemory ((p), (q), (s)), (p)) |
||||
|
#define SCOT_MEM_FILL(p,v,s) (FillMemory ((p), (s), (v)), (p)) |
||||
|
#define SCOT_MEM_ZERO ZeroMemory |
||||
|
#define SCOT_STR_LENGTH str_length |
||||
|
#define SCOT_STR_COPY str_copy |
||||
|
#define SCOT_STRN_COPY strn_copy |
||||
|
#define SCOT_STR_CHAR str_char |
||||
|
#define SCOT_STRR_CHAR strr_char |
||||
|
|
||||
|
SIZE_T str_length (const char *); |
||||
|
char * str_copy (char *, const char *); |
||||
|
char * strn_copy (char *, const char *, SIZE_T); |
||||
|
char * str_char (const char *, int); |
||||
|
char * strr_char (const char *, int); |
||||
|
|
||||
|
#endif /* MEMORY_H */ |
||||
@ -0,0 +1,6 @@ |
|||||
|
#ifndef SCOT_TYPES_H |
||||
|
#define SCOT_TYPES_H |
||||
|
|
||||
|
#include <Windows.h> |
||||
|
|
||||
|
#endif /* SCOT_TYPES_H */ |
||||
@ -0,0 +1,79 @@ |
|||||
|
/* |
||||
|
* used for threadsafety within exception |
||||
|
* actually only pthread is supported |
||||
|
*/ |
||||
|
#ifndef THREAD_H |
||||
|
#define THREAD_H |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <windows.h> |
||||
|
|
||||
|
|
||||
|
#define JOIN_OK 0x00 |
||||
|
#define JOIN_TIMEOUT 0x01 |
||||
|
#define JOIN_ERROR 0x02 |
||||
|
|
||||
|
/* |
||||
|
* i guess it is possible to write mutex code that uses cond |
||||
|
* elements to timeout on lock, but right now i have no clear |
||||
|
* idea of how to do this. The following thoughts i had: |
||||
|
* - create a struct that holds a pthread_mutex_t and a pthread_cond_t |
||||
|
* for every mutex. |
||||
|
* - lock mutexes only by calling pthread_cond_timedwait |
||||
|
* And here starts the problem...to do a cond_timedwait i need to ensure |
||||
|
* that the mutex is already locked...well and then a question i have not |
||||
|
* clearyfied, if a thread ends, will all locks on mutexes be removed? |
||||
|
* I guess so, but i did not test it. And an even more important question, |
||||
|
* is it possible to write cleanup-code that guarantees that a |
||||
|
* pthread_cond_signal is called for every mutex the thread holds... |
||||
|
* well, we will end up with the requirement that the programmer has to |
||||
|
* call a release mutex function before ending a thread and if the programmer |
||||
|
* forgets that the behaviour of out code is unspecified |
||||
|
* Right now i will not support timeouts on mutex-locks and to be consistent |
||||
|
* it is not supported on win32 either, also it would be much easier to |
||||
|
* implement there. |
||||
|
*/ |
||||
|
#define MUTEX_LOCK_OK 0x00 |
||||
|
#define MUTEX_LOCK_ERROR 0x02 |
||||
|
|
||||
|
#define THREAD_T HANDLE |
||||
|
#define THREAD_ID_T DWORD |
||||
|
#define THREAD_ID GetCurrentThreadId () |
||||
|
#define SELF_THREAD GetCurrentThread () |
||||
|
#define NEW_THREAD thread_new |
||||
|
#define CANCEL_THREAD(thread) (! TerminateThread ((thread), -1)) |
||||
|
#define EXIT_THREAD(retval) _endthreadex ((DWORD) (retval)) |
||||
|
#define JOIN_THREAD thread_join |
||||
|
#define THREAD_CANCEL_ENABLE |
||||
|
#define THREAD_CANCEL_DISABLE |
||||
|
#define THREAD_CANCEL_ASYNC |
||||
|
#define THREAD_CANCEL_DEFER |
||||
|
#define T_PROC_RET DWORD WINAPI |
||||
|
|
||||
|
#define THREAD_MUTEX_T HANDLE |
||||
|
#define NEW_THREAD_MUTEX CreateMutex (NULL, FALSE, NULL) |
||||
|
#define LOCK_THREAD_MUTEX thread_mutex_lock |
||||
|
#define UNLOCK_THREAD_MUTEX(mutex) (! ReleaseMutex ((mutex))) |
||||
|
|
||||
|
#define THREAD_COND_T CONDITION_VARIABLE |
||||
|
#define THREAD_COND_CS_T CRITICAL_SECTION |
||||
|
#define GET_THREAD_COND(c) |
||||
|
#define GET_THREAD_COND_CS(c) |
||||
|
#define THREAD_COND_ENTER_CS(cs) EnterCriticalSection ((cs)) |
||||
|
#define THREAD_COND_LEAVE_CS(cs) LeaveCriticalSection ((cs)) |
||||
|
#define SIGNAL_THREAD_COND(cond) WakeConditionVariable ((cond)) |
||||
|
#define BCAST_THREAD_COND(cond) WakeAllConditionVariable ((cond)) |
||||
|
#define WAIT_THREAD_COND(cond, cs, t) \ |
||||
|
SleepConditionVariableCS((cond), (cs), t) |
||||
|
|
||||
|
#define THREAD_ATEXIT_BEGIN |
||||
|
#define THREAD_ATEXIT_END |
||||
|
|
||||
|
typedef T_PROC_RET (*scot_thread_entry_fptr) (void *); |
||||
|
|
||||
|
THREAD_T thread_new (T_PROC_RET (*)(void *), void*); |
||||
|
int thread_join (THREAD_T, unsigned int); |
||||
|
THREAD_MUTEX_T thread_mutex_new (void); |
||||
|
int thread_mutex_lock (THREAD_MUTEX_T *); |
||||
|
|
||||
|
#endif /* THREAD_H */ |
||||
@ -0,0 +1,98 @@ |
|||||
|
/* |
||||
|
* scot_common.h: commen difinitions for scot. |
||||
|
* scot is a c obliging toolbox. |
||||
|
* |
||||
|
* Copyright (C) 2006 Georg Steffers. All rights reserved. |
||||
|
* |
||||
|
* This software is licensed under the terms of the GNU Genral Public |
||||
|
* License (GPL). Please see gpl.txt for details or refer to |
||||
|
* http://www.gnu.org/licenses/gpl.html |
||||
|
* |
||||
|
* Author: Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* 01/22/2006: Georg Steffers - introduced to give support for gettext |
||||
|
* to all code used in san. |
||||
|
* 01/24/2006: Georg Steffers - introduce some new macros: |
||||
|
* SANTEXTDOMAIN -> textdomain for messages |
||||
|
* given by libsan functions. |
||||
|
* LOCALDIR -> directory where to find that |
||||
|
* textdomain. |
||||
|
* D_(s) -> translates with the |
||||
|
* SANTEXTDOMAIN. This should be |
||||
|
* called for strings defined |
||||
|
* within san. But remember to |
||||
|
* call |
||||
|
* bindtextdomain ( |
||||
|
* SANTEXTDOMAIN, LOCALEDIR); |
||||
|
* first. |
||||
|
*/ |
||||
|
#ifndef SCOT_COMMOM_H |
||||
|
#define SCOT_COMMON_H |
||||
|
|
||||
|
#include <locale.h> |
||||
|
#include <libintl.h> |
||||
|
#include <ctype.h> |
||||
|
#include <scot/scot_int.h> |
||||
|
|
||||
|
/* for PACKAGE and LOCALEDIR */ |
||||
|
#ifdef HAVE_CONFIG_H |
||||
|
#include "../config.h" |
||||
|
#else |
||||
|
#define PACKAGE "scot" |
||||
|
#define LOCALEDIR "/usr/share/locale" |
||||
|
#endif /* HAVE_CONFIG_H */ |
||||
|
|
||||
|
#define _(string) gettext(string) /* our mark for xgettext */ |
||||
|
#define D_(s) dgettext(PACKAGE, s) |
||||
|
/* a mark dgettext calls */ |
||||
|
#define N_(string) (string) /* noop mark for gettext */ |
||||
|
|
||||
|
/* inline for C++, GCC, C99. For C89 these macros are empty. */ |
||||
|
#if defined(__cplusplus) |
||||
|
# define STATIC_INLINE static inline |
||||
|
# define INLINE inline |
||||
|
scot/# define EXTERN_INLINE inline |
||||
|
#elif defined(__GNUC__) |
||||
|
# define STATIC_INLINE static __inline__ |
||||
|
# define INLINE static __inline__ |
||||
|
# define EXTERN_INLINE extern __inline__ |
||||
|
#elif __STDC_VERSION__ >= 199901 |
||||
|
# define STATIC_INLINE static inline |
||||
|
# define INLINE static inline |
||||
|
# define EXTERN_INLINE inline |
||||
|
#else /* C89 */ |
||||
|
# define STATIC_INLINE static |
||||
|
# define INLINE static |
||||
|
# define EXTERN_INLINE |
||||
|
#endif /* inline definitions */ |
||||
|
|
||||
|
#define SCOT_SOCKET_BACKLOG 5 |
||||
|
|
||||
|
/*int scot_strisdigit (const char *);*/ |
||||
|
#ifndef SCOT_STRISDIGIT |
||||
|
#define SCOT_STRISDIGIT scot_strisdigit |
||||
|
static |
||||
|
inline |
||||
|
int scot_strisdigit (const char * str) |
||||
|
{ |
||||
|
while (*str) |
||||
|
if (!isdigit (*(str++))) return 0; |
||||
|
return 1; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#ifndef UNIX_PATH_MAX |
||||
|
/* |
||||
|
* this should be done better....i got this val from linux/un.h but as |
||||
|
* this should be portable i should think about a more portable way to get |
||||
|
* this...maybe with configure.... |
||||
|
*/ |
||||
|
#define UNIX_PATH_MAX 108 |
||||
|
#endif /* UNIX_PATH_MAX */ |
||||
|
|
||||
|
#define SCOT_UNX_PATH_TO_LONG 0 |
||||
|
extern const char * scot_common_errmsg[]; |
||||
|
|
||||
|
int base2exp (uint32_t); |
||||
|
|
||||
|
#endif /* SCOT_COMMON_H */ |
||||
@ -0,0 +1 @@ |
|||||
|
EXTRA_DIST = codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 intmax.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 longdouble.m4 longlong.m4 nls.m4 po.m4 printf-posix.m4 progtest.m4 signed.m4 size_max.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 wchar_t.m4 wint_t.m4 xsize.m4 |
||||
@ -0,0 +1,685 @@ |
|||||
|
dnl @synopsis AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])] |
||||
|
dnl |
||||
|
dnl the "ISO C9X: 7.18 Integer types <stdint.h>" section requires the |
||||
|
dnl existence of an include file <stdint.h> that defines a set of |
||||
|
dnl typedefs, especially uint8_t,int32_t,uintptr_t. Many older |
||||
|
dnl installations will not provide this file, but some will have the |
||||
|
dnl very same definitions in <inttypes.h>. In other enviroments we can |
||||
|
dnl use the inet-types in <sys/types.h> which would define the typedefs |
||||
|
dnl int8_t and u_int8_t respectivly. |
||||
|
dnl |
||||
|
dnl This macros will create a local "_stdint.h" or the headerfile given |
||||
|
dnl as an argument. In many cases that file will just "#include |
||||
|
dnl <stdint.h>" or "#include <inttypes.h>", while in other environments |
||||
|
dnl it will provide the set of basic 'stdint's definitions/typedefs: |
||||
|
dnl |
||||
|
dnl int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t |
||||
|
dnl int_least32_t.. int_fast32_t.. intmax_t |
||||
|
dnl |
||||
|
dnl which may or may not rely on the definitions of other files, or |
||||
|
dnl using the AC_CHECK_SIZEOF macro to determine the actual sizeof each |
||||
|
dnl type. |
||||
|
dnl |
||||
|
dnl if your header files require the stdint-types you will want to |
||||
|
dnl create an installable file mylib-int.h that all your other |
||||
|
dnl installable header may include. So if you have a library package |
||||
|
dnl named "mylib", just use |
||||
|
dnl |
||||
|
dnl AX_CREATE_STDINT_H(mylib-int.h) |
||||
|
dnl |
||||
|
dnl in configure.ac and go to install that very header file in |
||||
|
dnl Makefile.am along with the other headers (mylib.h) - and the |
||||
|
dnl mylib-specific headers can simply use "#include <mylib-int.h>" to |
||||
|
dnl obtain the stdint-types. |
||||
|
dnl |
||||
|
dnl Remember, if the system already had a valid <stdint.h>, the |
||||
|
dnl generated file will include it directly. No need for fuzzy |
||||
|
dnl HAVE_STDINT_H things... |
||||
|
dnl |
||||
|
dnl @category C |
||||
|
dnl @author Guido Draheim <guidod@gmx.de> |
||||
|
dnl @version 2003-12-07 |
||||
|
dnl @license GPLWithACException |
||||
|
|
||||
|
AC_DEFUN([AX_CHECK_DATA_MODEL],[ |
||||
|
AC_CHECK_SIZEOF(char) |
||||
|
AC_CHECK_SIZEOF(short) |
||||
|
AC_CHECK_SIZEOF(int) |
||||
|
AC_CHECK_SIZEOF(long) |
||||
|
AC_CHECK_SIZEOF(void*) |
||||
|
ac_cv_char_data_model="" |
||||
|
ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_char" |
||||
|
ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_short" |
||||
|
ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_int" |
||||
|
ac_cv_long_data_model="" |
||||
|
ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_int" |
||||
|
ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_long" |
||||
|
ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_voidp" |
||||
|
AC_MSG_CHECKING([data model]) |
||||
|
case "$ac_cv_char_data_model/$ac_cv_long_data_model" in |
||||
|
122/242) ac_cv_data_model="IP16" ; n="standard 16bit machine" ;; |
||||
|
122/244) ac_cv_data_model="LP32" ; n="standard 32bit machine" ;; |
||||
|
122/*) ac_cv_data_model="i16" ; n="unusual int16 model" ;; |
||||
|
124/444) ac_cv_data_model="ILP32" ; n="standard 32bit unixish" ;; |
||||
|
124/488) ac_cv_data_model="LP64" ; n="standard 64bit unixish" ;; |
||||
|
124/448) ac_cv_data_model="LLP64" ; n="unusual 64bit unixish" ;; |
||||
|
124/*) ac_cv_data_model="i32" ; n="unusual int32 model" ;; |
||||
|
128/888) ac_cv_data_model="ILP64" ; n="unusual 64bit numeric" ;; |
||||
|
128/*) ac_cv_data_model="i64" ; n="unusual int64 model" ;; |
||||
|
222/*2) ac_cv_data_model="DSP16" ; n="strict 16bit dsptype" ;; |
||||
|
333/*3) ac_cv_data_model="DSP24" ; n="strict 24bit dsptype" ;; |
||||
|
444/*4) ac_cv_data_model="DSP32" ; n="strict 32bit dsptype" ;; |
||||
|
666/*6) ac_cv_data_model="DSP48" ; n="strict 48bit dsptype" ;; |
||||
|
888/*8) ac_cv_data_model="DSP64" ; n="strict 64bit dsptype" ;; |
||||
|
222/*|333/*|444/*|666/*|888/*) : |
||||
|
ac_cv_data_model="iDSP" ; n="unusual dsptype" ;; |
||||
|
*) ac_cv_data_model="none" ; n="very unusual model" ;; |
||||
|
esac |
||||
|
AC_MSG_RESULT([$ac_cv_data_model ($ac_cv_long_data_model, $n)]) |
||||
|
]) |
||||
|
|
||||
|
dnl AX_CHECK_HEADER_STDINT_X([HEADERLIST][,ACTION-IF]) |
||||
|
AC_DEFUN([AX_CHECK_HEADER_STDINT_X],[ |
||||
|
AC_CACHE_CHECK([for stdint uintptr_t], [ac_cv_header_stdint_x],[ |
||||
|
ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h) |
||||
|
AC_MSG_RESULT([(..)]) |
||||
|
for i in m4_ifval([$1],[$1],[stdint.h inttypes.h sys/inttypes.h]) ; do |
||||
|
unset ac_cv_type_uintptr_t |
||||
|
unset ac_cv_type_uint64_t |
||||
|
AC_CHECK_TYPE(uintptr_t,[ac_cv_header_stdint_x=$i],continue,[#include <$i>]) |
||||
|
AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) |
||||
|
m4_ifvaln([$1],[$1]) break |
||||
|
done |
||||
|
AC_MSG_CHECKING([for stdint uintptr_t]) |
||||
|
]) |
||||
|
]) |
||||
|
|
||||
|
AC_DEFUN([AX_CHECK_HEADER_STDINT_O],[ |
||||
|
AC_CACHE_CHECK([for stdint uint32_t], [ac_cv_header_stdint_o],[ |
||||
|
ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h) |
||||
|
AC_MSG_RESULT([(..)]) |
||||
|
for i in m4_ifval([$1],[$1],[inttypes.h sys/inttypes.h stdint.h]) ; do |
||||
|
unset ac_cv_type_uint32_t |
||||
|
unset ac_cv_type_uint64_t |
||||
|
AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],continue,[#include <$i>]) |
||||
|
AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) |
||||
|
m4_ifvaln([$1],[$1]) break |
||||
|
break; |
||||
|
done |
||||
|
AC_MSG_CHECKING([for stdint uint32_t]) |
||||
|
]) |
||||
|
]) |
||||
|
|
||||
|
AC_DEFUN([AX_CHECK_HEADER_STDINT_U],[ |
||||
|
AC_CACHE_CHECK([for stdint u_int32_t], [ac_cv_header_stdint_u],[ |
||||
|
ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h) |
||||
|
AC_MSG_RESULT([(..)]) |
||||
|
for i in m4_ifval([$1],[$1],[sys/types.h inttypes.h sys/inttypes.h]) ; do |
||||
|
unset ac_cv_type_u_int32_t |
||||
|
unset ac_cv_type_u_int64_t |
||||
|
AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],continue,[#include <$i>]) |
||||
|
AC_CHECK_TYPE(u_int64_t,[and64="/u_int64_t"],[and64=""],[#include<$i>]) |
||||
|
m4_ifvaln([$1],[$1]) break |
||||
|
break; |
||||
|
done |
||||
|
AC_MSG_CHECKING([for stdint u_int32_t]) |
||||
|
]) |
||||
|
]) |
||||
|
|
||||
|
AC_DEFUN([AX_CREATE_STDINT_H], |
||||
|
[# ------ AX CREATE STDINT H ------------------------------------- |
||||
|
AC_MSG_CHECKING([for stdint types]) |
||||
|
ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` |
||||
|
# try to shortcircuit - if the default include path of the compiler |
||||
|
# can find a "stdint.h" header then we assume that all compilers can. |
||||
|
AC_CACHE_VAL([ac_cv_header_stdint_t],[ |
||||
|
old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS="" |
||||
|
old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="" |
||||
|
old_CFLAGS="$CFLAGS" ; CFLAGS="" |
||||
|
AC_TRY_COMPILE([#include <stdint.h>],[int_least32_t v = 0;], |
||||
|
[ac_cv_stdint_result="(assuming C99 compatible system)" |
||||
|
ac_cv_header_stdint_t="stdint.h"; ], |
||||
|
[ac_cv_header_stdint_t=""]) |
||||
|
CXXFLAGS="$old_CXXFLAGS" |
||||
|
CPPFLAGS="$old_CPPFLAGS" |
||||
|
CFLAGS="$old_CFLAGS" ]) |
||||
|
|
||||
|
v="... $ac_cv_header_stdint_h" |
||||
|
if test "$ac_stdint_h" = "stdint.h" ; then |
||||
|
AC_MSG_RESULT([(are you sure you want them in ./stdint.h?)]) |
||||
|
elif test "$ac_stdint_h" = "inttypes.h" ; then |
||||
|
AC_MSG_RESULT([(are you sure you want them in ./inttypes.h?)]) |
||||
|
elif test "_$ac_cv_header_stdint_t" = "_" ; then |
||||
|
AC_MSG_RESULT([(putting them into $ac_stdint_h)$v]) |
||||
|
else |
||||
|
ac_cv_header_stdint="$ac_cv_header_stdint_t" |
||||
|
AC_MSG_RESULT([$ac_cv_header_stdint (shortcircuit)]) |
||||
|
fi |
||||
|
|
||||
|
if test "_$ac_cv_header_stdint_t" = "_" ; then # can not shortcircuit.. |
||||
|
|
||||
|
dnl .....intro message done, now do a few system checks..... |
||||
|
dnl btw, all old CHECK_TYPE macros do automatically "DEFINE" a type, |
||||
|
dnl therefore we use the autoconf implementation detail CHECK_TYPE_NEW |
||||
|
dnl instead that is triggered with 3 or more arguments (see types.m4) |
||||
|
|
||||
|
inttype_headers=`echo $2 | sed -e 's/,/ /g'` |
||||
|
|
||||
|
ac_cv_stdint_result="(no helpful system typedefs seen)" |
||||
|
AX_CHECK_HEADER_STDINT_X(dnl |
||||
|
stdint.h inttypes.h sys/inttypes.h $inttype_headers, |
||||
|
ac_cv_stdint_result="(seen uintptr_t$and64 in $i)") |
||||
|
|
||||
|
if test "_$ac_cv_header_stdint_x" = "_" ; then |
||||
|
AX_CHECK_HEADER_STDINT_O(dnl, |
||||
|
inttypes.h sys/inttypes.h stdint.h $inttype_headers, |
||||
|
ac_cv_stdint_result="(seen uint32_t$and64 in $i)") |
||||
|
fi |
||||
|
|
||||
|
if test "_$ac_cv_header_stdint_x" = "_" ; then |
||||
|
if test "_$ac_cv_header_stdint_o" = "_" ; then |
||||
|
AX_CHECK_HEADER_STDINT_U(dnl, |
||||
|
sys/types.h inttypes.h sys/inttypes.h $inttype_headers, |
||||
|
ac_cv_stdint_result="(seen u_int32_t$and64 in $i)") |
||||
|
fi fi |
||||
|
|
||||
|
dnl if there was no good C99 header file, do some typedef checks... |
||||
|
if test "_$ac_cv_header_stdint_x" = "_" ; then |
||||
|
AC_MSG_CHECKING([for stdint datatype model]) |
||||
|
AC_MSG_RESULT([(..)]) |
||||
|
AX_CHECK_DATA_MODEL |
||||
|
fi |
||||
|
|
||||
|
if test "_$ac_cv_header_stdint_x" != "_" ; then |
||||
|
ac_cv_header_stdint="$ac_cv_header_stdint_x" |
||||
|
elif test "_$ac_cv_header_stdint_o" != "_" ; then |
||||
|
ac_cv_header_stdint="$ac_cv_header_stdint_o" |
||||
|
elif test "_$ac_cv_header_stdint_u" != "_" ; then |
||||
|
ac_cv_header_stdint="$ac_cv_header_stdint_u" |
||||
|
else |
||||
|
ac_cv_header_stdint="stddef.h" |
||||
|
fi |
||||
|
|
||||
|
AC_MSG_CHECKING([for extra inttypes in chosen header]) |
||||
|
AC_MSG_RESULT([($ac_cv_header_stdint)]) |
||||
|
dnl see if int_least and int_fast types are present in _this_ header. |
||||
|
unset ac_cv_type_int_least32_t |
||||
|
unset ac_cv_type_int_fast32_t |
||||
|
AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) |
||||
|
AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) |
||||
|
AC_CHECK_TYPE(intmax_t,,,[#include <$ac_cv_header_stdint>]) |
||||
|
|
||||
|
fi # shortcircut to system "stdint.h" |
||||
|
# ------------------ PREPARE VARIABLES ------------------------------ |
||||
|
if test "$GCC" = "yes" ; then |
||||
|
ac_cv_stdint_message="using gnu compiler "`$CC --version | head -n 1` |
||||
|
else |
||||
|
ac_cv_stdint_message="using $CC" |
||||
|
fi |
||||
|
|
||||
|
AC_MSG_RESULT([make use of $ac_cv_header_stdint in $ac_stdint_h dnl |
||||
|
$ac_cv_stdint_result]) |
||||
|
|
||||
|
dnl ----------------------------------------------------------------- |
||||
|
# ----------------- DONE inttypes.h checks START header ------------- |
||||
|
AC_CONFIG_COMMANDS([$ac_stdint_h],[ |
||||
|
AC_MSG_NOTICE(creating $ac_stdint_h : $_ac_stdint_h) |
||||
|
ac_stdint=$tmp/_stdint.h |
||||
|
|
||||
|
echo "#ifndef" $_ac_stdint_h >$ac_stdint |
||||
|
echo "#define" $_ac_stdint_h "1" >>$ac_stdint |
||||
|
echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint |
||||
|
echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint |
||||
|
echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint |
||||
|
if test "_$ac_cv_header_stdint_t" != "_" ; then |
||||
|
echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint |
||||
|
echo "#include <stdint.h>" >>$ac_stdint |
||||
|
echo "#endif" >>$ac_stdint |
||||
|
echo "#endif" >>$ac_stdint |
||||
|
else |
||||
|
|
||||
|
cat >>$ac_stdint <<STDINT_EOF |
||||
|
|
||||
|
/* ................... shortcircuit part ........................... */ |
||||
|
|
||||
|
#if defined HAVE_STDINT_H || defined _STDINT_HAVE_STDINT_H |
||||
|
#include <stdint.h> |
||||
|
#else |
||||
|
#include <stddef.h> |
||||
|
|
||||
|
/* .................... configured part ............................ */ |
||||
|
|
||||
|
STDINT_EOF |
||||
|
|
||||
|
echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint |
||||
|
if test "_$ac_cv_header_stdint_x" != "_" ; then |
||||
|
ac_header="$ac_cv_header_stdint_x" |
||||
|
echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint |
||||
|
else |
||||
|
echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint |
||||
|
fi |
||||
|
|
||||
|
echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint |
||||
|
if test "_$ac_cv_header_stdint_o" != "_" ; then |
||||
|
ac_header="$ac_cv_header_stdint_o" |
||||
|
echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint |
||||
|
else |
||||
|
echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint |
||||
|
fi |
||||
|
|
||||
|
echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint |
||||
|
if test "_$ac_cv_header_stdint_u" != "_" ; then |
||||
|
ac_header="$ac_cv_header_stdint_u" |
||||
|
echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint |
||||
|
else |
||||
|
echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint |
||||
|
fi |
||||
|
|
||||
|
echo "" >>$ac_stdint |
||||
|
|
||||
|
if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then |
||||
|
echo "#include <$ac_header>" >>$ac_stdint |
||||
|
echo "" >>$ac_stdint |
||||
|
fi fi |
||||
|
|
||||
|
echo "/* which 64bit typedef has been found */" >>$ac_stdint |
||||
|
if test "$ac_cv_type_uint64_t" = "yes" ; then |
||||
|
echo "#define _STDINT_HAVE_UINT64_T" "1" >>$ac_stdint |
||||
|
else |
||||
|
echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint |
||||
|
fi |
||||
|
if test "$ac_cv_type_u_int64_t" = "yes" ; then |
||||
|
echo "#define _STDINT_HAVE_U_INT64_T" "1" >>$ac_stdint |
||||
|
else |
||||
|
echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint |
||||
|
fi |
||||
|
echo "" >>$ac_stdint |
||||
|
|
||||
|
echo "/* which type model has been detected */" >>$ac_stdint |
||||
|
if test "_$ac_cv_char_data_model" != "_" ; then |
||||
|
echo "#define _STDINT_CHAR_MODEL" "$ac_cv_char_data_model" >>$ac_stdint |
||||
|
echo "#define _STDINT_LONG_MODEL" "$ac_cv_long_data_model" >>$ac_stdint |
||||
|
else |
||||
|
echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint |
||||
|
echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint |
||||
|
fi |
||||
|
echo "" >>$ac_stdint |
||||
|
|
||||
|
echo "/* whether int_least types were detected */" >>$ac_stdint |
||||
|
if test "$ac_cv_type_int_least32_t" = "yes"; then |
||||
|
echo "#define _STDINT_HAVE_INT_LEAST32_T" "1" >>$ac_stdint |
||||
|
else |
||||
|
echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint |
||||
|
fi |
||||
|
echo "/* whether int_fast types were detected */" >>$ac_stdint |
||||
|
if test "$ac_cv_type_int_fast32_t" = "yes"; then |
||||
|
echo "#define _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint |
||||
|
else |
||||
|
echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint |
||||
|
fi |
||||
|
echo "/* whether intmax_t type was detected */" >>$ac_stdint |
||||
|
if test "$ac_cv_type_intmax_t" = "yes"; then |
||||
|
echo "#define _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint |
||||
|
else |
||||
|
echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint |
||||
|
fi |
||||
|
echo "" >>$ac_stdint |
||||
|
|
||||
|
cat >>$ac_stdint <<STDINT_EOF |
||||
|
/* .................... detections part ............................ */ |
||||
|
|
||||
|
/* whether we need to define bitspecific types from compiler base types */ |
||||
|
#ifndef _STDINT_HEADER_INTPTR |
||||
|
#ifndef _STDINT_HEADER_UINT32 |
||||
|
#ifndef _STDINT_HEADER_U_INT32 |
||||
|
#define _STDINT_NEED_INT_MODEL_T |
||||
|
#else |
||||
|
#define _STDINT_HAVE_U_INT_TYPES |
||||
|
#endif |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#ifdef _STDINT_HAVE_U_INT_TYPES |
||||
|
#undef _STDINT_NEED_INT_MODEL_T |
||||
|
#endif |
||||
|
|
||||
|
#ifdef _STDINT_CHAR_MODEL |
||||
|
#if _STDINT_CHAR_MODEL+0 == 122 || _STDINT_CHAR_MODEL+0 == 124 |
||||
|
#ifndef _STDINT_BYTE_MODEL |
||||
|
#define _STDINT_BYTE_MODEL 12 |
||||
|
#endif |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#ifndef _STDINT_HAVE_INT_LEAST32_T |
||||
|
#define _STDINT_NEED_INT_LEAST_T |
||||
|
#endif |
||||
|
|
||||
|
#ifndef _STDINT_HAVE_INT_FAST32_T |
||||
|
#define _STDINT_NEED_INT_FAST_T |
||||
|
#endif |
||||
|
|
||||
|
#ifndef _STDINT_HEADER_INTPTR |
||||
|
#define _STDINT_NEED_INTPTR_T |
||||
|
#ifndef _STDINT_HAVE_INTMAX_T |
||||
|
#define _STDINT_NEED_INTMAX_T |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
/* .................... definition part ............................ */ |
||||
|
|
||||
|
/* some system headers have good uint64_t */ |
||||
|
#ifndef _HAVE_UINT64_T |
||||
|
#if defined _STDINT_HAVE_UINT64_T || defined HAVE_UINT64_T |
||||
|
#define _HAVE_UINT64_T |
||||
|
#elif defined _STDINT_HAVE_U_INT64_T || defined HAVE_U_INT64_T |
||||
|
#define _HAVE_UINT64_T |
||||
|
typedef u_int64_t uint64_t; |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#ifndef _HAVE_UINT64_T |
||||
|
/* .. here are some common heuristics using compiler runtime specifics */ |
||||
|
#if defined __STDC_VERSION__ && defined __STDC_VERSION__ >= 199901L |
||||
|
#define _HAVE_UINT64_T |
||||
|
#define _HAVE_LONGLONG_UINT64_T |
||||
|
typedef long long int64_t; |
||||
|
typedef unsigned long long uint64_t; |
||||
|
|
||||
|
#elif !defined __STRICT_ANSI__ |
||||
|
#if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ |
||||
|
#define _HAVE_UINT64_T |
||||
|
typedef __int64 int64_t; |
||||
|
typedef unsigned __int64 uint64_t; |
||||
|
|
||||
|
#elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ |
||||
|
/* note: all ELF-systems seem to have loff-support which needs 64-bit */ |
||||
|
#if !defined _NO_LONGLONG |
||||
|
#define _HAVE_UINT64_T |
||||
|
#define _HAVE_LONGLONG_UINT64_T |
||||
|
typedef long long int64_t; |
||||
|
typedef unsigned long long uint64_t; |
||||
|
#endif |
||||
|
|
||||
|
#elif defined __alpha || (defined __mips && defined _ABIN32) |
||||
|
#if !defined _NO_LONGLONG |
||||
|
typedef long int64_t; |
||||
|
typedef unsigned long uint64_t; |
||||
|
#endif |
||||
|
/* compiler/cpu type to define int64_t */ |
||||
|
#endif |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#if defined _STDINT_HAVE_U_INT_TYPES |
||||
|
/* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */ |
||||
|
typedef u_int8_t uint8_t; |
||||
|
typedef u_int16_t uint16_t; |
||||
|
typedef u_int32_t uint32_t; |
||||
|
|
||||
|
/* glibc compatibility */ |
||||
|
#ifndef __int8_t_defined |
||||
|
#define __int8_t_defined |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#ifdef _STDINT_NEED_INT_MODEL_T |
||||
|
/* we must guess all the basic types. Apart from byte-adressable system, */ |
||||
|
/* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */ |
||||
|
/* (btw, those nibble-addressable systems are way off, or so we assume) */ |
||||
|
|
||||
|
dnl /* have a look at "64bit and data size neutrality" at */ |
||||
|
dnl /* http://unix.org/version2/whatsnew/login_64bit.html */ |
||||
|
dnl /* (the shorthand "ILP" types always have a "P" part) */ |
||||
|
|
||||
|
#if defined _STDINT_BYTE_MODEL |
||||
|
#if _STDINT_LONG_MODEL+0 == 242 |
||||
|
/* 2:4:2 = IP16 = a normal 16-bit system */ |
||||
|
typedef unsigned char uint8_t; |
||||
|
typedef unsigned short uint16_t; |
||||
|
typedef unsigned long uint32_t; |
||||
|
#ifndef __int8_t_defined |
||||
|
#define __int8_t_defined |
||||
|
typedef char int8_t; |
||||
|
typedef short int16_t; |
||||
|
typedef long int32_t; |
||||
|
#endif |
||||
|
#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444 |
||||
|
/* 2:4:4 = LP32 = a 32-bit system derived from a 16-bit */ |
||||
|
/* 4:4:4 = ILP32 = a normal 32-bit system */ |
||||
|
typedef unsigned char uint8_t; |
||||
|
typedef unsigned short uint16_t; |
||||
|
typedef unsigned int uint32_t; |
||||
|
#ifndef __int8_t_defined |
||||
|
#define __int8_t_defined |
||||
|
typedef char int8_t; |
||||
|
typedef short int16_t; |
||||
|
typedef int int32_t; |
||||
|
#endif |
||||
|
#elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488 |
||||
|
/* 4:8:4 = IP32 = a 32-bit system prepared for 64-bit */ |
||||
|
/* 4:8:8 = LP64 = a normal 64-bit system */ |
||||
|
typedef unsigned char uint8_t; |
||||
|
typedef unsigned short uint16_t; |
||||
|
typedef unsigned int uint32_t; |
||||
|
#ifndef __int8_t_defined |
||||
|
#define __int8_t_defined |
||||
|
typedef char int8_t; |
||||
|
typedef short int16_t; |
||||
|
typedef int int32_t; |
||||
|
#endif |
||||
|
/* this system has a "long" of 64bit */ |
||||
|
#ifndef _HAVE_UINT64_T |
||||
|
#define _HAVE_UINT64_T |
||||
|
typedef unsigned long uint64_t; |
||||
|
typedef long int64_t; |
||||
|
#endif |
||||
|
#elif _STDINT_LONG_MODEL+0 == 448 |
||||
|
/* LLP64 a 64-bit system derived from a 32-bit system */ |
||||
|
typedef unsigned char uint8_t; |
||||
|
typedef unsigned short uint16_t; |
||||
|
typedef unsigned int uint32_t; |
||||
|
#ifndef __int8_t_defined |
||||
|
#define __int8_t_defined |
||||
|
typedef char int8_t; |
||||
|
typedef short int16_t; |
||||
|
typedef int int32_t; |
||||
|
#endif |
||||
|
/* assuming the system has a "long long" */ |
||||
|
#ifndef _HAVE_UINT64_T |
||||
|
#define _HAVE_UINT64_T |
||||
|
#define _HAVE_LONGLONG_UINT64_T |
||||
|
typedef unsigned long long uint64_t; |
||||
|
typedef long long int64_t; |
||||
|
#endif |
||||
|
#else |
||||
|
#define _STDINT_NO_INT32_T |
||||
|
#endif |
||||
|
#else |
||||
|
#define _STDINT_NO_INT8_T |
||||
|
#define _STDINT_NO_INT32_T |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
/* |
||||
|
* quote from SunOS-5.8 sys/inttypes.h: |
||||
|
* Use at your own risk. As of February 1996, the committee is squarely |
||||
|
* behind the fixed sized types; the "least" and "fast" types are still being |
||||
|
* discussed. The probability that the "fast" types may be removed before |
||||
|
* the standard is finalized is high enough that they are not currently |
||||
|
* implemented. |
||||
|
*/ |
||||
|
|
||||
|
#if defined _STDINT_NEED_INT_LEAST_T |
||||
|
typedef int8_t int_least8_t; |
||||
|
typedef int16_t int_least16_t; |
||||
|
typedef int32_t int_least32_t; |
||||
|
#ifdef _HAVE_UINT64_T |
||||
|
typedef int64_t int_least64_t; |
||||
|
#endif |
||||
|
|
||||
|
typedef uint8_t uint_least8_t; |
||||
|
typedef uint16_t uint_least16_t; |
||||
|
typedef uint32_t uint_least32_t; |
||||
|
#ifdef _HAVE_UINT64_T |
||||
|
typedef uint64_t uint_least64_t; |
||||
|
#endif |
||||
|
/* least types */ |
||||
|
#endif |
||||
|
|
||||
|
#if defined _STDINT_NEED_INT_FAST_T |
||||
|
typedef int8_t int_fast8_t; |
||||
|
typedef int int_fast16_t; |
||||
|
typedef int32_t int_fast32_t; |
||||
|
#ifdef _HAVE_UINT64_T |
||||
|
typedef int64_t int_fast64_t; |
||||
|
#endif |
||||
|
|
||||
|
typedef uint8_t uint_fast8_t; |
||||
|
typedef unsigned uint_fast16_t; |
||||
|
typedef uint32_t uint_fast32_t; |
||||
|
#ifdef _HAVE_UINT64_T |
||||
|
typedef uint64_t uint_fast64_t; |
||||
|
#endif |
||||
|
/* fast types */ |
||||
|
#endif |
||||
|
|
||||
|
#ifdef _STDINT_NEED_INTMAX_T |
||||
|
#ifdef _HAVE_UINT64_T |
||||
|
typedef int64_t intmax_t; |
||||
|
typedef uint64_t uintmax_t; |
||||
|
#else |
||||
|
typedef long intmax_t; |
||||
|
typedef unsigned long uintmax_t; |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#ifdef _STDINT_NEED_INTPTR_T |
||||
|
#ifndef __intptr_t_defined |
||||
|
#define __intptr_t_defined |
||||
|
/* we encourage using "long" to store pointer values, never use "int" ! */ |
||||
|
#if _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484 |
||||
|
typedef unsinged int uintptr_t; |
||||
|
typedef int intptr_t; |
||||
|
#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444 |
||||
|
typedef unsigned long uintptr_t; |
||||
|
typedef long intptr_t; |
||||
|
#elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T |
||||
|
typedef uint64_t uintptr_t; |
||||
|
typedef int64_t intptr_t; |
||||
|
#else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */ |
||||
|
typedef unsigned long uintptr_t; |
||||
|
typedef long intptr_t; |
||||
|
#endif |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
/* The ISO C99 standard specifies that in C++ implementations these |
||||
|
should only be defined if explicitly requested. */ |
||||
|
#if !defined __cplusplus || defined __STDC_CONSTANT_MACROS |
||||
|
#ifndef UINT32_C |
||||
|
|
||||
|
/* Signed. */ |
||||
|
# define INT8_C(c) c |
||||
|
# define INT16_C(c) c |
||||
|
# define INT32_C(c) c |
||||
|
# ifdef _HAVE_LONGLONG_UINT64_T |
||||
|
# define INT64_C(c) c ## L |
||||
|
# else |
||||
|
# define INT64_C(c) c ## LL |
||||
|
# endif |
||||
|
|
||||
|
/* Unsigned. */ |
||||
|
# define UINT8_C(c) c ## U |
||||
|
# define UINT16_C(c) c ## U |
||||
|
# define UINT32_C(c) c ## U |
||||
|
# ifdef _HAVE_LONGLONG_UINT64_T |
||||
|
# define UINT64_C(c) c ## UL |
||||
|
# else |
||||
|
# define UINT64_C(c) c ## ULL |
||||
|
# endif |
||||
|
|
||||
|
/* Maximal type. */ |
||||
|
# ifdef _HAVE_LONGLONG_UINT64_T |
||||
|
# define INTMAX_C(c) c ## L |
||||
|
# define UINTMAX_C(c) c ## UL |
||||
|
# else |
||||
|
# define INTMAX_C(c) c ## LL |
||||
|
# define UINTMAX_C(c) c ## ULL |
||||
|
# endif |
||||
|
|
||||
|
/* literalnumbers */ |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
/* These limits are merily those of a two complement byte-oriented system */ |
||||
|
|
||||
|
/* Minimum of signed integral types. */ |
||||
|
# define INT8_MIN (-128) |
||||
|
# define INT16_MIN (-32767-1) |
||||
|
# define INT32_MIN (-2147483647-1) |
||||
|
# define INT64_MIN (-__INT64_C(9223372036854775807)-1) |
||||
|
/* Maximum of signed integral types. */ |
||||
|
# define INT8_MAX (127) |
||||
|
# define INT16_MAX (32767) |
||||
|
# define INT32_MAX (2147483647) |
||||
|
# define INT64_MAX (__INT64_C(9223372036854775807)) |
||||
|
|
||||
|
/* Maximum of unsigned integral types. */ |
||||
|
# define UINT8_MAX (255) |
||||
|
# define UINT16_MAX (65535) |
||||
|
# define UINT32_MAX (4294967295U) |
||||
|
# define UINT64_MAX (__UINT64_C(18446744073709551615)) |
||||
|
|
||||
|
/* Minimum of signed integral types having a minimum size. */ |
||||
|
# define INT_LEAST8_MIN INT8_MIN |
||||
|
# define INT_LEAST16_MIN INT16_MIN |
||||
|
# define INT_LEAST32_MIN INT32_MIN |
||||
|
# define INT_LEAST64_MIN INT64_MIN |
||||
|
/* Maximum of signed integral types having a minimum size. */ |
||||
|
# define INT_LEAST8_MAX INT8_MAX |
||||
|
# define INT_LEAST16_MAX INT16_MAX |
||||
|
# define INT_LEAST32_MAX INT32_MAX |
||||
|
# define INT_LEAST64_MAX INT64_MAX |
||||
|
|
||||
|
/* Maximum of unsigned integral types having a minimum size. */ |
||||
|
# define UINT_LEAST8_MAX UINT8_MAX |
||||
|
# define UINT_LEAST16_MAX UINT16_MAX |
||||
|
# define UINT_LEAST32_MAX UINT32_MAX |
||||
|
# define UINT_LEAST64_MAX UINT64_MAX |
||||
|
|
||||
|
/* shortcircuit*/ |
||||
|
#endif |
||||
|
/* once */ |
||||
|
#endif |
||||
|
#endif |
||||
|
STDINT_EOF |
||||
|
fi |
||||
|
if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then |
||||
|
AC_MSG_NOTICE([$ac_stdint_h is unchanged]) |
||||
|
else |
||||
|
ac_dir=`AS_DIRNAME(["$ac_stdint_h"])` |
||||
|
AS_MKDIR_P(["$ac_dir"]) |
||||
|
rm -f $ac_stdint_h |
||||
|
mv $ac_stdint $ac_stdint_h |
||||
|
fi |
||||
|
],[# variables for create stdint.h replacement |
||||
|
PACKAGE="$PACKAGE" |
||||
|
VERSION="$VERSION" |
||||
|
ac_stdint_h="$ac_stdint_h" |
||||
|
_ac_stdint_h=AS_TR_CPP(_$PACKAGE-$ac_stdint_h) |
||||
|
ac_cv_stdint_message="$ac_cv_stdint_message" |
||||
|
ac_cv_header_stdint_t="$ac_cv_header_stdint_t" |
||||
|
ac_cv_header_stdint_x="$ac_cv_header_stdint_x" |
||||
|
ac_cv_header_stdint_o="$ac_cv_header_stdint_o" |
||||
|
ac_cv_header_stdint_u="$ac_cv_header_stdint_u" |
||||
|
ac_cv_type_uint64_t="$ac_cv_type_uint64_t" |
||||
|
ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" |
||||
|
ac_cv_char_data_model="$ac_cv_char_data_model" |
||||
|
ac_cv_long_data_model="$ac_cv_long_data_model" |
||||
|
ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" |
||||
|
ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" |
||||
|
ac_cv_type_intmax_t="$ac_cv_type_intmax_t" |
||||
|
]) |
||||
|
]) |
||||
@ -0,0 +1,61 @@ |
|||||
|
LTLIBS = $(INTLLIBS) |
||||
|
LIBS = $(INTLLIBS) |
||||
|
|
||||
|
LTLIBS += @THREAD_LIB@ @SOCK_LIB@ |
||||
|
LIBS += @THREAD_LIB@ @SOCK_LIB@ |
||||
|
|
||||
|
INCLUDES = -I../include @INOTIFY_INCLUDES@ |
||||
|
|
||||
|
libscot_source = scot_common.c cmdla.c \
|
||||
|
list.c stack.c queue.c \
|
||||
|
thread.c dir.c \
|
||||
|
exception.c scot_exceptions.c \
|
||||
|
stream.c stream_ctl.c socket.c socket_in.c \
|
||||
|
event.c event_listener.c \
|
||||
|
stream_pool_base.c stream_pool_management.c \
|
||||
|
stream_pool_fraction.c spf_thread_impl.c |
||||
|
|
||||
|
BUILT_SOURCES = thread.c memory.c dir.c spf_thread_impl.c stream_ctl.c |
||||
|
CLEANFILES = thread.c memory.c dir.c spf_thread_impl.c stream_ctl.c |
||||
|
|
||||
|
if PTHREAD |
||||
|
thread.c: Makefile posix/thread.c |
||||
|
cp posix/thread.c ./thread.c |
||||
|
else |
||||
|
thread.c: Makefile win32/thread.c |
||||
|
cp win32/thread.c ./thread.c |
||||
|
endif |
||||
|
|
||||
|
if WIN32 |
||||
|
libscot_source += memory.c stream_win.c |
||||
|
|
||||
|
stream_ctl.c: Makefile win32/stream_ctl.c |
||||
|
cp win32/stream_ctl.c ./stream_ctl.c |
||||
|
spf_thread_impl.c: Makefile win32/spf_thread_impl.c |
||||
|
cp win32/spf_thread_impl.c ./spf_thread_impl.c |
||||
|
memory.c: Makefile win32/memory.c |
||||
|
cp win32/memory.c ./memory.c |
||||
|
dir.c: Makefile win32/dir.c |
||||
|
cp win32/dir.c ./dir.c |
||||
|
else |
||||
|
libscot_source += socket_un.c fs_watcher.c |
||||
|
|
||||
|
stream_ctl.c: Makefile posix/stream_ctl.c |
||||
|
cp posix/stream_ctl.c ./stream_ctl.c |
||||
|
spf_thread_impl.c: Makefile posix/spf_thread_impl.c |
||||
|
cp posix/spf_thread_impl.c ./spf_thread_impl.c |
||||
|
memory.c: Makefile |
||||
|
touch memory.c |
||||
|
dir.c: Makefile posix/dir.c |
||||
|
cp posix/dir.c ./dir.c |
||||
|
endif |
||||
|
|
||||
|
lib_LTLIBRARIES = libscot.la |
||||
|
|
||||
|
libscot_la_SOURCES = $(libscot_source) |
||||
|
libscot_la_LDFLAGS = -version-info 0:3:0 -no-undefined |
||||
|
libscot_la_CFLAGS = @THREAD_CFLAGS@ |
||||
|
|
||||
|
# install: install-am
|
||||
|
# strip -x $(DESTDIR)$(libdir)/libscot.so.0.0.2
|
||||
|
# strip -x $(DESTDIR)$(libdir)/libscot.a
|
||||
@ -0,0 +1,408 @@ |
|||||
|
/* |
||||
|
* cmdla.c: Some small function to make command line argument parsing |
||||
|
* more convinient. Actually this is only intended for single |
||||
|
* character arguments. |
||||
|
* COMMENT: This is only appropriate for default application that do not |
||||
|
* want to do special things like assining same parameters to |
||||
|
* different files. For an example of such an application see sox. |
||||
|
* But this behavier can be, at least to some level achieved by |
||||
|
* using an appropriate callback, that saves all paramters in a |
||||
|
* special manner, associated to the given filename that in turn |
||||
|
* needs to be an option too. |
||||
|
* |
||||
|
* Copyright (C) 2006 Georg Steffers. All rights reserved. |
||||
|
* |
||||
|
* This software is licensed under the terms of the GNU Genral Public |
||||
|
* License (GPL). Please see gpl.txt for details or refer to |
||||
|
* http://www.gnu.org/licenses/gpl.html |
||||
|
* |
||||
|
* Author: Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* 01/14/2006: Georg Steffers - First implemented |
||||
|
* 01/15/2006: Georg Steffers - V0.1 ready. Modified this and that. |
||||
|
* now long arguments are supported as |
||||
|
* well as arguments with am optional |
||||
|
* parameter. |
||||
|
* 01/23/2006: Georg Steffers - add support for gettext. |
||||
|
* 01/24/2006: Georg Steffers - changes so that cmdla uses the textdomain |
||||
|
* of san (the lib cmdla belongs to) for the |
||||
|
* few strings that introduces itself, namely |
||||
|
* "help", "gives this help", "switches", |
||||
|
* "arguments" and the formatstring |
||||
|
* "usage: %s [%s] [%s] %s". All other |
||||
|
* strings given to process_cmd_line from |
||||
|
* within a program are translated with |
||||
|
* the textdomain of that program, e.g. |
||||
|
* the function should always be called with |
||||
|
* the untranslated strings. This is done to make |
||||
|
* it possible to call it with constant strings |
||||
|
* declared before any call of bindtextdomain |
||||
|
* or textdomain. |
||||
|
*/ |
||||
|
|
||||
|
#define MAX_ARGS 200 |
||||
|
|
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <unistd.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#include <scot/cmdla.h> |
||||
|
#include <scot/memory.h> |
||||
|
|
||||
|
/* |
||||
|
* search for an appropriate cb to @name in @pcbs and @scbs and call |
||||
|
* it. If none is found call the help cb. |
||||
|
*/ |
||||
|
static |
||||
|
int |
||||
|
call_cb ( |
||||
|
const struct cmdlap_cbt *pcbs, |
||||
|
const struct cmdlas_cbt *scbs, |
||||
|
const char *optarg, |
||||
|
const char *name, |
||||
|
const char val) |
||||
|
{ |
||||
|
int cbs_idx; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
cbs_idx = 0; |
||||
|
while (pcbs[cbs_idx].cb != NULL) |
||||
|
{ |
||||
|
if ((name != NULL && pcbs[cbs_idx].sarg == name) || |
||||
|
(val != 0 && pcbs[cbs_idx].carg == val)) |
||||
|
{ |
||||
|
switch (pcbs[cbs_idx].cmdla_argt) { |
||||
|
case CMDLA_REQ_ARG: |
||||
|
if (optarg == NULL) |
||||
|
return call_cb (pcbs, scbs, optarg, D_("help"), '?'); |
||||
|
|
||||
|
/* we got an arg, so fallthrough CMDLA_OPT_ARG to get |
||||
|
* it processed */ |
||||
|
case CMDLA_OPT_ARG: |
||||
|
return |
||||
|
pcbs[cbs_idx].cb ( |
||||
|
optarg, |
||||
|
pcbs[cbs_idx].cmdla_type, |
||||
|
pcbs[cbs_idx].var); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
cbs_idx++; |
||||
|
} |
||||
|
|
||||
|
cbs_idx = 0; |
||||
|
while (scbs[cbs_idx].cb != NULL) |
||||
|
{ |
||||
|
if ((name != NULL && scbs[cbs_idx].sarg == name) || |
||||
|
(val != 0 && scbs[cbs_idx].carg == val)) |
||||
|
return scbs[cbs_idx].cb (scbs[cbs_idx].var); |
||||
|
|
||||
|
cbs_idx++; |
||||
|
} |
||||
|
|
||||
|
return call_cb (pcbs, scbs, optarg, D_("help"), '?'); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* If no usage_cb is given to cmdla, then create a basic default usage. |
||||
|
*/ |
||||
|
int |
||||
|
default_usage_cb (void *info) |
||||
|
{ |
||||
|
struct du_infot *du_infop; |
||||
|
const struct cmdlas_cbt *sw; |
||||
|
const struct cmdlap_cbt *ar; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
du_infop = (struct du_infot *) info; |
||||
|
sw = du_infop->switches; |
||||
|
ar = du_infop->arguments; |
||||
|
|
||||
|
if (du_infop->about != NULL) |
||||
|
fprintf (stderr, du_infop->about); |
||||
|
|
||||
|
if (du_infop->copyright != NULL) |
||||
|
{ |
||||
|
fprintf (stderr, "\n\n"); |
||||
|
fprintf (stderr, du_infop->copyright); |
||||
|
} |
||||
|
|
||||
|
fprintf (stderr, "\n\n"); |
||||
|
fprintf ( |
||||
|
stderr, |
||||
|
D_("Usage: %s [%s] [%s] %s"), |
||||
|
du_infop->program_name, |
||||
|
D_("switches"), D_("arguments"), |
||||
|
du_infop->usage_aa != NULL ? du_infop->usage_aa : ""); |
||||
|
fprintf (stderr, "\n\n"); |
||||
|
|
||||
|
fprintf (stderr, "\t%s: \n", D_("switches")); |
||||
|
|
||||
|
while (sw != NULL && sw->cb != NULL) |
||||
|
{ |
||||
|
fprintf ( |
||||
|
stderr, |
||||
|
"\t %c%c%s%-7s : %-45s\n", |
||||
|
sw->carg != 0 ? '-' : ' ', |
||||
|
sw->carg != 0 ? sw->carg : ' ', |
||||
|
(sw->sarg != NULL && |
||||
|
sw->carg != 0) ? " / --" : |
||||
|
(sw->sarg != NULL && |
||||
|
sw->carg == 0) ? " --" : " ", |
||||
|
sw->sarg != NULL ? sw->sarg : "", |
||||
|
sw->info != NULL ? sw->info : ""); |
||||
|
|
||||
|
sw++; |
||||
|
} |
||||
|
|
||||
|
fprintf (stderr, "\t%s: \n", D_("arguments")); |
||||
|
|
||||
|
while (ar != NULL && ar->cb != NULL) |
||||
|
{ |
||||
|
fprintf ( |
||||
|
stderr, |
||||
|
"\t %c%c%-8s%s%s%-10s : %-20s\n", |
||||
|
ar->carg != 0 ? '-' : ' ', |
||||
|
ar->carg != 0 ? ar->carg : ' ', |
||||
|
(ar->cmdla_argt != CMDLA_OPT_ARG && |
||||
|
ar->carg != 0) ? "[ ]<val>" : |
||||
|
(ar->carg == 0) ? "" : "[val]", |
||||
|
(ar->sarg != NULL && |
||||
|
ar->carg != 0) ? " | --" : |
||||
|
(ar->sarg != NULL && |
||||
|
ar->carg == 0) ? " --" : " ", |
||||
|
ar->sarg != NULL ? ar->sarg : "", |
||||
|
(ar->cmdla_argt != CMDLA_OPT_ARG && |
||||
|
ar->sarg != NULL) ? "[=| ]<val>" : |
||||
|
(ar->sarg == NULL) ? "" : "[=val]", |
||||
|
ar->info != NULL ? ar->info : ""); |
||||
|
|
||||
|
ar++; |
||||
|
} |
||||
|
|
||||
|
exit(-1); |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
switch_cb (void *arg) |
||||
|
{ |
||||
|
int * sw = (int *) arg; |
||||
|
|
||||
|
*sw = (*sw == 0)?1:0; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
inc_cb (void *arg) |
||||
|
{ |
||||
|
int * sw = (int *) arg; |
||||
|
|
||||
|
*sw = *sw + 1; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* The default callback for process_cmd_line to get a parameter saved to |
||||
|
* a variable of the correct type. |
||||
|
* Converts @param to the Type specified in the @type and saves it into |
||||
|
* the pointer to a variable delivered in @arg |
||||
|
*/ |
||||
|
int |
||||
|
get_cmdlap_cb ( |
||||
|
const char *param, |
||||
|
const int cmdla_type, |
||||
|
void *arg) |
||||
|
{ |
||||
|
if (param != NULL) |
||||
|
switch (cmdla_type) |
||||
|
{ |
||||
|
case CMDLA_TYPE_STRING: |
||||
|
* (const char **) arg = param; |
||||
|
break; |
||||
|
case CMDLA_TYPE_INT: |
||||
|
sscanf (param, "%d", (int *) arg); |
||||
|
break; |
||||
|
case CMDLA_TYPE_FLOAT: |
||||
|
sscanf (param, "%f", (float *) arg); |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Processes command line patameters |
||||
|
*/ |
||||
|
int |
||||
|
process_cmd_line ( |
||||
|
int argc, |
||||
|
char *argv[], |
||||
|
const char *about, |
||||
|
const char *copyright, |
||||
|
const char *usage_aa, /* usage additional args */ |
||||
|
const struct cmdlap_cbt *pcbs, |
||||
|
const struct cmdlas_cbt *scbs) |
||||
|
{ |
||||
|
char optstring[MAX_ARGS]; |
||||
|
int option_index = 0; |
||||
|
struct option long_opts[MAX_ARGS]; |
||||
|
|
||||
|
int cbs_idx, optstring_idx, long_opts_idx; |
||||
|
int has_u = 0; |
||||
|
int ch; |
||||
|
|
||||
|
struct cmdlas_cbt switches[MAX_ARGS]; |
||||
|
struct cmdlap_cbt arguments[MAX_ARGS]; |
||||
|
|
||||
|
struct du_infot du_info = { |
||||
|
switches, arguments, _(about), _(copyright), _(usage_aa), argv[0] }; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
/* |
||||
|
* Every command line argument, either with or without an additional |
||||
|
* parameter is associated with a callback function, which in turn |
||||
|
* does the neccessaty initialization. Callbacks for switches get an |
||||
|
* void* as parameter and callbacks for parameter arguments get the |
||||
|
* parameter as a const char*, the datatype the parameter has and |
||||
|
* a pointer to the variable that should hold the parameter throughout |
||||
|
* the program. |
||||
|
*/ |
||||
|
|
||||
|
/* |
||||
|
* create optstring and long_opts for getopt_long(). |
||||
|
* As this should be called with the untranslated messages |
||||
|
* we need to call _() to put the translated ones into optstring |
||||
|
* and long_opts. Also we need to update the values in switches and |
||||
|
* arguments must be converted to the translated strings. |
||||
|
*/ |
||||
|
|
||||
|
/* Zero out optsting and long_opts */ |
||||
|
SCOT_MEM_FILL (optstring, 0, MAX_ARGS); |
||||
|
SCOT_MEM_FILL (long_opts, 0, MAX_ARGS * sizeof (struct option)); |
||||
|
|
||||
|
/* zero switches and copy scbs to switches */ |
||||
|
SCOT_MEM_FILL (switches, 0, MAX_ARGS * sizeof (struct cmdlas_cbt)); |
||||
|
cbs_idx = 0; |
||||
|
while (scbs != NULL && scbs[cbs_idx].cb != NULL) |
||||
|
{ |
||||
|
SCOT_MEM_COPY ( |
||||
|
&(switches[cbs_idx]), |
||||
|
&(scbs[cbs_idx]), |
||||
|
sizeof (struct cmdlas_cbt)); |
||||
|
switches[cbs_idx].sarg = _(scbs[cbs_idx].sarg); |
||||
|
switches[cbs_idx].info = _(scbs[cbs_idx].info); |
||||
|
|
||||
|
cbs_idx++; |
||||
|
} |
||||
|
|
||||
|
/* zero arguments and copy scbs to switches */ |
||||
|
SCOT_MEM_FILL (arguments, 0, MAX_ARGS * sizeof (struct cmdlap_cbt)); |
||||
|
cbs_idx = 0; |
||||
|
while (pcbs != NULL && pcbs[cbs_idx].cb != NULL) |
||||
|
{ |
||||
|
SCOT_MEM_COPY ( |
||||
|
&(arguments[cbs_idx]), |
||||
|
&(pcbs[cbs_idx]), |
||||
|
sizeof (struct cmdlap_cbt)); |
||||
|
arguments[cbs_idx].sarg = _(pcbs[cbs_idx].sarg); |
||||
|
arguments[cbs_idx].info = _(pcbs[cbs_idx].info); |
||||
|
|
||||
|
cbs_idx++; |
||||
|
} |
||||
|
|
||||
|
/* walk through arguments */ |
||||
|
cbs_idx = optstring_idx = long_opts_idx = 0; |
||||
|
while (arguments != NULL && arguments[cbs_idx].cb != NULL) { |
||||
|
if (arguments[cbs_idx].carg != 0) |
||||
|
{ |
||||
|
optstring[optstring_idx++] = arguments[cbs_idx].carg; |
||||
|
|
||||
|
if (arguments[cbs_idx].carg == '?') |
||||
|
{ |
||||
|
has_u = 1; |
||||
|
if (switches[cbs_idx].var == NULL) |
||||
|
{ |
||||
|
switches[cbs_idx].var = (void *) &du_info; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
switch (arguments[cbs_idx].cmdla_argt) |
||||
|
{ |
||||
|
case CMDLA_OPT_ARG: optstring[optstring_idx++] = ':'; |
||||
|
case CMDLA_REQ_ARG: optstring[optstring_idx++] = ':'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (pcbs[cbs_idx].sarg != NULL) |
||||
|
{ |
||||
|
long_opts[long_opts_idx].name = arguments[cbs_idx].sarg; |
||||
|
long_opts[long_opts_idx].has_arg = arguments[cbs_idx].cmdla_argt; |
||||
|
long_opts[long_opts_idx].val = arguments[cbs_idx].carg; |
||||
|
long_opts_idx++; |
||||
|
} |
||||
|
|
||||
|
cbs_idx++; |
||||
|
} |
||||
|
|
||||
|
/* and now through switches */ |
||||
|
cbs_idx = 0; |
||||
|
while (switches != NULL && switches[cbs_idx].cb != NULL) { |
||||
|
if (switches[cbs_idx].carg != 0) |
||||
|
optstring[optstring_idx++] = switches[cbs_idx].carg; |
||||
|
|
||||
|
if (switches[cbs_idx].carg == '?') |
||||
|
has_u = 1; |
||||
|
|
||||
|
if (switches[cbs_idx].sarg != NULL) |
||||
|
{ |
||||
|
long_opts[long_opts_idx].name = switches[cbs_idx].sarg; |
||||
|
long_opts[long_opts_idx].val = switches[cbs_idx].carg; |
||||
|
long_opts_idx++; |
||||
|
} |
||||
|
|
||||
|
cbs_idx++; |
||||
|
} |
||||
|
|
||||
|
/* if no usage callback is give use our default usage */ |
||||
|
if (has_u == 0) |
||||
|
{ |
||||
|
switches[cbs_idx].carg = '?'; |
||||
|
switches[cbs_idx].sarg = D_("help"); |
||||
|
switches[cbs_idx].cb = default_usage_cb; |
||||
|
switches[cbs_idx].var = (void *) &du_info; |
||||
|
switches[cbs_idx].info = D_("gives this help"); |
||||
|
cbs_idx++; |
||||
|
SCOT_MEM_FILL (&(switches[cbs_idx]), 0, sizeof (struct cmdlas_cbt)); |
||||
|
|
||||
|
optstring[optstring_idx++] = '?'; |
||||
|
long_opts[long_opts_idx].name = D_("help"); |
||||
|
long_opts[long_opts_idx].val = '?'; |
||||
|
long_opts_idx++; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Now parse the command line arguments. |
||||
|
* Check if the argument appears in switch_cids, or in param_cids, or |
||||
|
* of the don't if there is a '?'-switch defined and call the |
||||
|
* appropriate cb if possible. |
||||
|
*/ |
||||
|
ch = getopt_long (argc, argv, optstring, long_opts, &option_index); |
||||
|
while (ch != EOF) |
||||
|
{ |
||||
|
const char *name; |
||||
|
|
||||
|
if (ch == 0) |
||||
|
name = long_opts[option_index].name; |
||||
|
else |
||||
|
name = NULL; |
||||
|
|
||||
|
call_cb (arguments, switches, optarg, name, ch); |
||||
|
|
||||
|
ch = getopt_long (argc, argv, optstring, long_opts, &option_index); |
||||
|
} |
||||
|
|
||||
|
return optind; |
||||
|
} |
||||
@ -0,0 +1,348 @@ |
|||||
|
#include <scot/memory.h> |
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/event.h> |
||||
|
#include <scot/scot_int.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
/* |
||||
|
* !!! REALLY IMPORTANT !!! |
||||
|
* If there is extra data to an event, and the event sould be serializable, |
||||
|
* one has to ensure that ed points to already network byteorder |
||||
|
* converted data. Else there might occur problems when sending the data |
||||
|
* to another machine with a different byteorder. |
||||
|
*/ |
||||
|
struct scot_event * |
||||
|
scot_event_new (struct scot_event * e, SCOT_EVENT_NO no, void * ed, SIZE_T eds) |
||||
|
{ |
||||
|
if (e == NULL) |
||||
|
{ |
||||
|
e = SCOT_MEM_GET (sizeof (struct scot_event)); |
||||
|
SCOT_MEM_ZERO (e, sizeof (struct scot_event)); |
||||
|
} |
||||
|
|
||||
|
e->event = no; |
||||
|
|
||||
|
e->size = sizeof (SCOT_EVENT_NO); |
||||
|
e->size += sizeof (SIZE_T); |
||||
|
|
||||
|
if (ed != NULL) |
||||
|
{ |
||||
|
e->extra_data = SCOT_MEM_GET (eds); |
||||
|
SCOT_MEM_COPY (e->extra_data, ed, eds); |
||||
|
e->ed_size = eds; |
||||
|
e->size += eds; |
||||
|
} |
||||
|
|
||||
|
e->size += sizeof (SIZE_T); |
||||
|
|
||||
|
return e; |
||||
|
} |
||||
|
|
||||
|
struct scot_stream_pool_event * |
||||
|
scot_stream_pool_event_new ( |
||||
|
struct scot_stream_pool_event * e, |
||||
|
SCOT_EVENT_NO no, |
||||
|
void * ed, |
||||
|
SIZE_T eds, |
||||
|
struct scot_stream * st) |
||||
|
{ |
||||
|
if (e == NULL) |
||||
|
{ |
||||
|
e = SCOT_MEM_GET (sizeof (struct scot_stream_pool_event)); |
||||
|
SCOT_MEM_ZERO (e, sizeof (struct scot_stream_pool_event)); |
||||
|
} |
||||
|
|
||||
|
e = (struct scot_stream_pool_event *) scot_event_new ( |
||||
|
(struct scot_event *) e, no, ed, eds); |
||||
|
|
||||
|
e->st = st; |
||||
|
|
||||
|
e->event.size += sizeof (struct scot_stream); |
||||
|
|
||||
|
return e; |
||||
|
} |
||||
|
|
||||
|
struct scot_fs_watcher_event * |
||||
|
scot_fs_watcher_event_new ( |
||||
|
struct scot_fs_watcher_event * e, |
||||
|
SCOT_EVENT_NO no, |
||||
|
void * ed, |
||||
|
SIZE_T eds, |
||||
|
const char * path, |
||||
|
const char * name, |
||||
|
const char * oldname) |
||||
|
{ |
||||
|
if (e == NULL) |
||||
|
{ |
||||
|
e = SCOT_MEM_GET (sizeof (struct scot_fs_watcher_event)); |
||||
|
SCOT_MEM_ZERO (e, sizeof (struct scot_fs_watcher_event)); |
||||
|
} |
||||
|
|
||||
|
e = (struct scot_fs_watcher_event *) scot_event_new ( |
||||
|
(struct scot_event *) e, no, ed, eds); |
||||
|
|
||||
|
e->path = SCOT_MEM_GET (SCOT_STR_LENGTH (path) + 1); |
||||
|
SCOT_STR_COPY (e->path, path); |
||||
|
|
||||
|
e->event.size += SCOT_STR_LENGTH (path) + 1; |
||||
|
|
||||
|
e->name = SCOT_MEM_GET (SCOT_STR_LENGTH (name) + 1); |
||||
|
SCOT_STR_COPY (e->name, name); |
||||
|
|
||||
|
e->event.size += SCOT_STR_LENGTH (name) + 1; |
||||
|
|
||||
|
if (oldname != NULL) |
||||
|
{ |
||||
|
e->oldname = SCOT_MEM_GET (SCOT_STR_LENGTH (oldname) + 1); |
||||
|
SCOT_STR_COPY (e->oldname, oldname); |
||||
|
|
||||
|
e->event.size += SCOT_STR_LENGTH (oldname) + 1; |
||||
|
} |
||||
|
else |
||||
|
e->event.size += 1; |
||||
|
|
||||
|
return e; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
scot_stream_pool_event_free (struct scot_stream_pool_event * e) |
||||
|
{} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
scot_fs_watcher_event_free (struct scot_fs_watcher_event * e) |
||||
|
{ |
||||
|
if (e->path != NULL) |
||||
|
SCOT_MEM_FREE (e->path); |
||||
|
|
||||
|
if (e->name != NULL) |
||||
|
SCOT_MEM_FREE (e->name); |
||||
|
|
||||
|
if (e->oldname != NULL) |
||||
|
SCOT_MEM_FREE (e->oldname); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* scot_event_free identifies the given event and call appropriate |
||||
|
* free methods for it. Thus only scot_event_free is exported to |
||||
|
* free any type of event. |
||||
|
* The same is true for serialize and deserialize. |
||||
|
*/ |
||||
|
void |
||||
|
scot_event_free (struct scot_event * e) |
||||
|
{ |
||||
|
if (e != NULL) |
||||
|
{ |
||||
|
if (SCOT_EVENT_CHK_GROUP (e->event, SCOT_EG_STREAM_POOL)) |
||||
|
scot_stream_pool_event_free ((struct scot_stream_pool_event *) e); |
||||
|
if (SCOT_EVENT_CHK_GROUP (e->event, SCOT_EG_FS_WATCHER)) |
||||
|
scot_fs_watcher_event_free ((struct scot_fs_watcher_event *) e); |
||||
|
|
||||
|
if (e->extra_data != NULL) |
||||
|
SCOT_MEM_FREE (e->extra_data); |
||||
|
|
||||
|
SCOT_MEM_FREE (e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Eine Sache die man unbedingt beachten sollte ist, das die serialisierten |
||||
|
* Daten unter umständen auf einer Maschine mit unterschiedlicher |
||||
|
* Byte-Order landen. Daher muessen alle Daten in Network Byteorder |
||||
|
* umgewandelt werden und beim deserialisieren wieder zurück. |
||||
|
*/ |
||||
|
static |
||||
|
void |
||||
|
scot_stream_pool_event_serialize (struct scot_stream_pool_event * e, char ** s) |
||||
|
{ |
||||
|
char * fill = *s; |
||||
|
|
||||
|
/* |
||||
|
* serialize the struct scot_stream item of a stream_pool_event. |
||||
|
* well, normally we don't send stream_pool_event to other machines, |
||||
|
* so it might look like bloat to convert every part of it to |
||||
|
* network byte order. But as we do it we are ready to send the if |
||||
|
* the need araises in future. |
||||
|
* But at least to send this information to other machines is kind of |
||||
|
* senseless, because handle is something completely different on |
||||
|
* windows and linux. |
||||
|
* |
||||
|
* Well, the htonl approch does only work with sockets on windows. |
||||
|
* Under linux it is unimportant what part of the union is used, as |
||||
|
* all are uint32_t. Serialization of the stream handle makes no |
||||
|
* sense at all, as it couldn't be used by the receiver anyway. |
||||
|
*/ |
||||
|
* (int32_t *)fill = htonl (e->st->handle.sock); |
||||
|
fill += 4; |
||||
|
SCOT_MEM_COPY (fill, e->st->rbuf, SCOT_STREAM_BUF_SIZE); |
||||
|
fill += SCOT_STREAM_BUF_SIZE; |
||||
|
SCOT_MEM_COPY (fill, e->st->wbuf, SCOT_STREAM_BUF_SIZE); |
||||
|
fill += SCOT_STREAM_BUF_SIZE; |
||||
|
* (uint32_t *)fill = htonl (e->st->rbuf_idx); |
||||
|
fill += 4; |
||||
|
* (uint32_t *)fill = htonl (e->st->wbuf_idx); |
||||
|
fill += 4; |
||||
|
* (uint32_t *)fill = htonl (e->st->s_type); |
||||
|
fill += 4; |
||||
|
|
||||
|
*s = fill; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
scot_fs_watcher_event_serialize (struct scot_fs_watcher_event * e, char ** s) |
||||
|
{ |
||||
|
char * fill = *s; |
||||
|
|
||||
|
/* |
||||
|
* zuerst fswi serialisieren.... |
||||
|
*/ |
||||
|
SCOT_STR_COPY (fill, e->path); |
||||
|
fill += SCOT_STR_LENGTH (e->path) + 1; |
||||
|
SCOT_STR_COPY (fill, e->name); |
||||
|
fill += SCOT_STR_LENGTH (e->name) + 1; |
||||
|
if (e->oldname != NULL) |
||||
|
SCOT_STR_COPY (fill, e->oldname); |
||||
|
else |
||||
|
SCOT_STR_COPY (fill, ""); |
||||
|
fill += SCOT_STR_LENGTH (fill) + 1; |
||||
|
|
||||
|
*s = fill; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
struct scot_event * |
||||
|
scot_stream_pool_event_deserialize ( |
||||
|
struct scot_stream_pool_event * e, const char * s) |
||||
|
{ |
||||
|
e->st = SCOT_MEM_GET (sizeof (struct scot_stream)); |
||||
|
|
||||
|
e->st->handle.sock = ntohl (* (int32_t *)s); |
||||
|
s += 4; |
||||
|
SCOT_MEM_COPY (e->st->rbuf, s, SCOT_STREAM_BUF_SIZE); |
||||
|
s += SCOT_STREAM_BUF_SIZE; |
||||
|
SCOT_MEM_COPY (e->st->wbuf, s, SCOT_STREAM_BUF_SIZE); |
||||
|
s += SCOT_STREAM_BUF_SIZE; |
||||
|
e->st->rbuf_idx = ntohl (* (uint32_t *)s); |
||||
|
s += 4; |
||||
|
e->st->wbuf_idx = ntohl (* (uint32_t *)s); |
||||
|
s += 4; |
||||
|
e->st->s_type = ntohl (* (uint32_t *)s); |
||||
|
|
||||
|
SCOT_MEM_COPY (e->st, s, sizeof (struct scot_stream)); |
||||
|
|
||||
|
return (struct scot_event *) e; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
struct scot_event * |
||||
|
scot_fs_watcher_event_deserialize ( |
||||
|
struct scot_fs_watcher_event * e, const char * s) |
||||
|
{ |
||||
|
e->path = SCOT_MEM_GET (SCOT_STR_LENGTH (s) + 1); |
||||
|
SCOT_STR_COPY (e->path, s); |
||||
|
s += SCOT_STR_LENGTH (s) + 1; |
||||
|
|
||||
|
e->name = SCOT_MEM_GET (SCOT_STR_LENGTH (s) + 1); |
||||
|
SCOT_STR_COPY (e->name, s); |
||||
|
s += SCOT_STR_LENGTH (s) + 1; |
||||
|
|
||||
|
e->oldname = SCOT_MEM_GET (SCOT_STR_LENGTH (s) + 1); |
||||
|
SCOT_STR_COPY (e->oldname, s); |
||||
|
|
||||
|
return (struct scot_event *) e; |
||||
|
} |
||||
|
|
||||
|
SIZE_T |
||||
|
scot_event_serialize (struct scot_event * e, char ** s) |
||||
|
{ |
||||
|
char * fill; |
||||
|
|
||||
|
*s = fill = SCOT_MEM_GET (e->size); |
||||
|
SCOT_MEM_ZERO (fill, e->size); |
||||
|
|
||||
|
* (SCOT_EVENT_NO *)fill = htons (e->event); |
||||
|
fill += 2; |
||||
|
* (uint32_t *)fill = htonl (e->size); |
||||
|
fill += 4; |
||||
|
* (uint32_t *)fill = htonl (e->ed_size); |
||||
|
fill += 4; |
||||
|
|
||||
|
/* |
||||
|
* every extra data must be available in Network Byteorder if the |
||||
|
* event should be serializable. |
||||
|
* This is important at an ..._event_new function, as the void * for |
||||
|
* extra_data should always point to data that is already converted |
||||
|
* to network byteorder. |
||||
|
*/ |
||||
|
if (e->extra_data != NULL) |
||||
|
{ |
||||
|
SCOT_MEM_COPY (fill, &e->extra_data, e->ed_size); |
||||
|
fill += e->ed_size; |
||||
|
} |
||||
|
|
||||
|
if (SCOT_EVENT_CHK_GROUP (e->event, SCOT_EG_STREAM_POOL)) |
||||
|
scot_stream_pool_event_serialize ( |
||||
|
(struct scot_stream_pool_event *) e, &fill); |
||||
|
if (SCOT_EVENT_CHK_GROUP (e->event, SCOT_EG_FS_WATCHER)) |
||||
|
scot_fs_watcher_event_serialize ( |
||||
|
(struct scot_fs_watcher_event *) e, &fill); |
||||
|
|
||||
|
return e->size; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* GANZ WICHTIG....für diese Funktion muß sichergestellt sein, daß |
||||
|
* s mindestens sizeof (SCOT_EVENT_NO) + sizeof (SIZE_T) bytes |
||||
|
* vom anfang einer gültigen event-serialisierung enthält. |
||||
|
* Sonst kann die größe logischerweise nicht ermittelt werden. |
||||
|
*/ |
||||
|
SIZE_T |
||||
|
scot_event_size_serial (struct scot_event * e, const char * s) |
||||
|
{ |
||||
|
return ntohl (* (uint32_t *)(s + sizeof (SCOT_EVENT_NO))); |
||||
|
} |
||||
|
|
||||
|
SCOT_EVENT_NO |
||||
|
scot_event_no_serial (struct scot_event * e, const char * s) |
||||
|
{ |
||||
|
return ntohs (* (SCOT_EVENT_NO *)s); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Hier sollte sichergestellt sein, das s ein komplettes serialisiertes |
||||
|
* event enthält. |
||||
|
*/ |
||||
|
struct scot_event * |
||||
|
scot_event_deserialize (struct scot_event * e, const char * s) |
||||
|
{ |
||||
|
SIZE_T size; |
||||
|
|
||||
|
size = scot_event_size_serial (e, s); |
||||
|
|
||||
|
e = SCOT_MEM_GET (size); |
||||
|
SCOT_MEM_ZERO (e, size); |
||||
|
|
||||
|
e->event = ntohs (* (SCOT_EVENT_NO *)s); |
||||
|
s += 2; |
||||
|
e->size = ntohl (* (uint32_t *)s); |
||||
|
s += 4; |
||||
|
e->ed_size = ntohl (* (uint32_t *)s); |
||||
|
s += 4; |
||||
|
|
||||
|
if (e->ed_size != 0) |
||||
|
{ |
||||
|
SCOT_MEM_COPY (&e->extra_data, s, e->ed_size); |
||||
|
s += e->ed_size; |
||||
|
} |
||||
|
|
||||
|
if (SCOT_EVENT_CHK_GROUP (e->event, SCOT_EG_STREAM_POOL)) |
||||
|
e = scot_stream_pool_event_deserialize ( |
||||
|
(struct scot_stream_pool_event *) e, s); |
||||
|
if (SCOT_EVENT_CHK_GROUP (e->event, SCOT_EG_FS_WATCHER)) |
||||
|
e = scot_fs_watcher_event_deserialize ( |
||||
|
(struct scot_fs_watcher_event *) e, s); |
||||
|
|
||||
|
return e; |
||||
|
} |
||||
@ -0,0 +1,157 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <limits.h> |
||||
|
|
||||
|
#include <scot/scot_int.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
#include <scot/event_listener.h> |
||||
|
#include <scot/event.h> |
||||
|
#include <scot/thread.h> |
||||
|
#include <scot/exception.h> |
||||
|
|
||||
|
#define GEN_LOCAL |
||||
|
#include <scot/list.h> |
||||
|
#include <scot/stack.h> |
||||
|
#undef GEN_LOCAL |
||||
|
|
||||
|
#define EVENT_SOURCE_THREAD_CANCEL_WAIT_MAX INFINITE |
||||
|
|
||||
|
GEN_LIST (scot_event_cb_fptr); |
||||
|
GEN_STACK_FUNC_PROTO (scot_event_cb_fptr); |
||||
|
GEN_STACK_IMPL (scot_event_cb_fptr); |
||||
|
|
||||
|
void |
||||
|
scot_event_listener_init ( |
||||
|
struct scot_event_listener * l, |
||||
|
const unsigned char group, |
||||
|
const scot_thread_entry_fptr entry_func) |
||||
|
{ |
||||
|
l->group = group; |
||||
|
l->el_entry_func = entry_func; |
||||
|
|
||||
|
SCOT_MEM_ZERO (l->cb_mappings, |
||||
|
sizeof (stack_scot_event_cb_fptr_node_t *) * UCHAR_MAX); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_event_listener_fini ( |
||||
|
struct scot_event_listener * l) |
||||
|
{ |
||||
|
int i; |
||||
|
excenv_t *ee; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
if (THREAD_EQUAL (l->thread_id, THREAD_ID)) |
||||
|
THROW (EXC (EXC_ERROR, 102, "a event listener can't be destroyed from " |
||||
|
"its main thread.")); |
||||
|
|
||||
|
if (scot_event_listener_is_running (l)) |
||||
|
scot_event_listener_stop (l); |
||||
|
|
||||
|
for (i=0; i<UCHAR_MAX; i++) |
||||
|
if (l->cb_mappings[i] != NULL) |
||||
|
stack_scot_event_cb_fptr_free (l->cb_mappings[i]); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
printf ("Exception in %s (%s, %d)\n", __FUNCTION__, __FILE__, __LINE__); |
||||
|
forward_all_exceptions (ee); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_event_listener_start (struct scot_event_listener * l) |
||||
|
{ |
||||
|
NEW_THREAD (&l->thread_handle, l->el_entry_func, l); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_event_listener_stop (struct scot_event_listener * l) |
||||
|
{ |
||||
|
if (! scot_event_listener_is_running (l)) |
||||
|
return; |
||||
|
|
||||
|
if (l->thread_run_flg != 0) |
||||
|
{ |
||||
|
END_THREAD (l->thread_handle, SCOT_EL_WAIT_THREAD_MAX); |
||||
|
l->thread_run_flg = 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_event_listener_restart (struct scot_event_listener * l) |
||||
|
{ |
||||
|
scot_event_listener_stop (l); |
||||
|
scot_event_listener_start (l); |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
scot_event_listener_is_running (struct scot_event_listener * l) |
||||
|
{ |
||||
|
return l->thread_run_flg; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_event_listener_register_cb ( |
||||
|
struct scot_event_listener * l, |
||||
|
SCOT_EVENT_NO e, |
||||
|
scot_event_cb_fptr cb, |
||||
|
void * extra_data) |
||||
|
{ |
||||
|
excenv_t *ee; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
if ((e >> 8) != l->group) |
||||
|
THROW (EXC (EXC_ERROR, 101, |
||||
|
"[EVENT_SOURCE_REG_CB]Event not supported by listener")); |
||||
|
|
||||
|
if (l->cb_mappings[e&0x00FF] == NULL) |
||||
|
l->cb_mappings[e&0x00FF] = stack_scot_event_cb_fptr_new ( |
||||
|
l->cb_mappings[e&0x00FF]); |
||||
|
|
||||
|
stack_scot_event_cb_fptr_push ( |
||||
|
l->cb_mappings[e&0x00FF], |
||||
|
(scot_event_cb_fptr *)cb); |
||||
|
|
||||
|
l->cb_extra_data[e&0x00FF] = extra_data; |
||||
|
|
||||
|
/* restart listener after adding a callback. */ |
||||
|
if (scot_event_listener_is_running (l) != 0) |
||||
|
{ |
||||
|
scot_event_listener_stop (l); |
||||
|
scot_event_listener_start (l); |
||||
|
} |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
printf ("Exception in %s (%s, %d)\n", __FUNCTION__, __FILE__, __LINE__); |
||||
|
forward_all_exceptions (ee); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_event_listener_call_cb ( |
||||
|
struct scot_event_listener * l, |
||||
|
struct scot_event * e) |
||||
|
{ |
||||
|
SCOT_EVENT_NO eno = e->event; |
||||
|
|
||||
|
if (l->cb_mappings[e->event&0x00FF] != NULL) |
||||
|
{ |
||||
|
list_scot_event_cb_fptr_node_t * anchor = |
||||
|
LIST (scot_event_cb_fptr, l->cb_mappings[e->event&0x00FF]); |
||||
|
list_scot_event_cb_fptr_node_t * node = anchor; |
||||
|
|
||||
|
while (! list_scot_event_cb_fptr_eol (anchor, node)) |
||||
|
{ |
||||
|
scot_event_cb_fptr cb; |
||||
|
|
||||
|
node = list_scot_event_cb_fptr_next (node); |
||||
|
cb = (scot_event_cb_fptr) list_scot_event_cb_fptr_retrive (node); |
||||
|
|
||||
|
if (cb (e) == SCOT_EVENT_END) |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,157 @@ |
|||||
|
#include <scot/event_sink.h> |
||||
|
#include <scot/event_source.h> |
||||
|
#include <scot/event.h> |
||||
|
#include <scot/exception.h> |
||||
|
|
||||
|
#define GEN_LOCAL |
||||
|
#include <scot/queue.h> |
||||
|
#include <scot/list.h> |
||||
|
#undef GEN_LOCAL |
||||
|
|
||||
|
/* |
||||
|
struct scot_event_sink_event_wrapper |
||||
|
{ |
||||
|
struct scot_event_source es; |
||||
|
union scot_event_u e; |
||||
|
}; |
||||
|
|
||||
|
typedef struct scot_event_sink_event_wrapper scot_esew_t; |
||||
|
|
||||
|
GEN_QUEUE (scot_esew_t); |
||||
|
*/ |
||||
|
|
||||
|
typedef struct scot_event_sink scot_event_sink_t; |
||||
|
GEN_LIST (scot_event_sink_t); |
||||
|
|
||||
|
typedef struct scot_event_source scot_event_source_t; |
||||
|
GEN_LIST (scot_event_source_t); |
||||
|
|
||||
|
struct scot_event_manager |
||||
|
{ |
||||
|
list_scot_event_sink_t_node_t * sinks; |
||||
|
list_scot_event_source_t_node_t * sources; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
static |
||||
|
int |
||||
|
scot_event_source_compare_by_group_no ( |
||||
|
const struct scot_event_source * a, |
||||
|
const struct scot_event_source * b) |
||||
|
{ |
||||
|
return (a->group_no==b->group_no)?0:(a->group_no<b->group_no)?-1:1; |
||||
|
}; |
||||
|
|
||||
|
void |
||||
|
scot_event_manager_register_source ( |
||||
|
struct scot_event_manager * m, |
||||
|
struct scot_event_source * es) |
||||
|
{ |
||||
|
struct scot_event_manager_src_cb_map * s_cb_map; |
||||
|
|
||||
|
if (scot_event_source_set_manager (es, m) != 0) |
||||
|
THROW (EXC (EXC_ERROR, 1, "source already registered within other " |
||||
|
"manager.")); |
||||
|
|
||||
|
if (list_scot_event_source_t_find (m->sources, es)) |
||||
|
/* well, this source is already registered within this manager */ |
||||
|
{ |
||||
|
THROW (EXC (EXC_WARNING, 1, "event source already registered within " |
||||
|
"this manager.")); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
list_scot_event_source_t_node_t_set_cmp ( |
||||
|
scot_event_source_compare_by_group_no); |
||||
|
if (list_scot_event_source_t_find (m->sources, es)) |
||||
|
/* an event source of the same group is already registered within |
||||
|
* this manager */ |
||||
|
{ |
||||
|
THROW (EXC (EXC_WARNING, 1, "another event source of the same group " |
||||
|
"is already registered within this " |
||||
|
"manager.")); |
||||
|
return 0; |
||||
|
} |
||||
|
list_scot_event_source_t_node_t_set_cmp ( |
||||
|
list_scot_event_source_t_default_cmp); |
||||
|
|
||||
|
list_scot_event_source_t_add (m->sources, es); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_event_manager_register_sink ( |
||||
|
struct scot_event_manager * m, |
||||
|
struct scot_event_sink * es) |
||||
|
{ |
||||
|
if (scot_event_sink_set_manager (es, m) != 0) |
||||
|
THROW (EXC (EXC_ERROR, 2, "Sink already registered within other " |
||||
|
"manager.")); |
||||
|
list_scot_event_sink_t_add (m->sinks, s_cb_map); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_event_manager_call_cb ( |
||||
|
struct scot_event_manager * m, |
||||
|
struct scot_event_source * es, |
||||
|
struct scot_event * e) |
||||
|
{ |
||||
|
list_scot_emscm_t_node_t * emscm_node = m->src_cb; |
||||
|
|
||||
|
while (! list_scot_emscm_t_eol (m->src_cb, emscm_node)) |
||||
|
{ |
||||
|
struct scot_event_manager_src_cb_map * scbm; |
||||
|
|
||||
|
emscm_node = list_scot_emscm_t_next (emscm_node); |
||||
|
scbm = list_scot_emscm_t_retrive (emscm_node); |
||||
|
|
||||
|
if (scbm->source == es) |
||||
|
{ |
||||
|
scbm->cb (e); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_event_manager_dispatch_event ( |
||||
|
struct scot_event_manager * m, |
||||
|
struct scot_event * e, |
||||
|
struct scot_event_source * src, |
||||
|
int mask) |
||||
|
{ |
||||
|
list_event_sink_t_node_t * es_node = m->sinks; |
||||
|
int dipatched = 0; |
||||
|
|
||||
|
while (! list_scot_event_sink_t_node_t_eol (m->sinks, es_node)) |
||||
|
{ |
||||
|
struct scot_event_sink * es; |
||||
|
int i; |
||||
|
|
||||
|
es_node = list_scot_event_sink_t_next (es_node); |
||||
|
es = list_scot_event_sink_t_retrive (es_node); |
||||
|
|
||||
|
for (i=0; i<MAX_EVENT_GROUP && es->src[i]!=0; i++) |
||||
|
{ |
||||
|
if (es->src[i] == scot_event_get_src (e) && |
||||
|
es->mask[i] & scot_event_get_mask (e) != 0) |
||||
|
{ |
||||
|
/* Im folgenden sollte das nicht e sondern halt irgend eine |
||||
|
* art wrapper sein aus dem auch die gruppe und maske |
||||
|
* des events hervorgeht. |
||||
|
* sonst wird es unmöglich eine brauchbare Notice zu schicken |
||||
|
* wenn das event abgearbeitet wurde. */ |
||||
|
scot_event_sink_put_event (es, e); |
||||
|
dispatched = 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* wenn sich keine sink für das event interessiert hat. */ |
||||
|
if (dispatched == 0) |
||||
|
{ |
||||
|
/* einen etwaigen callback aufrufen... */ |
||||
|
scot_event_manager_call_bc (m, get_source from event(e), e); |
||||
|
/* resourcen des events freigeben... */ |
||||
|
scot_event_free (e); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
Das scot event subsystem versucht ein Abstraction layer auf beliebige |
||||
|
event systeme (auch selbst definierte) zu sein. |
||||
|
|
||||
|
Ich trenn Objeke (Strukture oder was auch immer) von der Event verarbeitung. |
||||
|
Das soll heißen, wenn ich ein Modul (struktur & funktionen) habe das |
||||
|
Xwindows erzeugt, anzeigt und maniputliert, so kann dieses Modul aber noch |
||||
|
nicht arbeiten, das es von sich aus nicht auf Events reagiert. Um es zum |
||||
|
arbeiten zu bringen muß man von einem Konkreten Xwindow (struktur gefüllt,etc) |
||||
|
eine X11_event_sink erzeugen. Diese kümmert sich um die Verarbeitung |
||||
|
von events (masken erzeugen, events eintragen, callbacks aufrufen, etc.). |
||||
|
Die event_sink muß noch in einen dispatcher eingetragen werden, der dann die |
||||
|
event_sink event Verarbeitungen auf eine bestimmte art und weise aufruft. |
||||
|
Dieser wird dann noch in einen dispatcher_manager eingetragen, der die |
||||
|
dispatcher ein oder ausschalten kann...evtl. brauch man dafür keinen |
||||
|
Manager sondern bietet zu dispatchern eben eine dispatcher_on, dispatcher_off |
||||
|
methode an. |
||||
|
Ein Objekt muß selbst die Methoden bieten, die eine passende event_sink |
||||
|
zu diesem objekt erzeugen. Dadurch kann ich z.B. ein erweiterte XWindow |
||||
|
Modul anlegen, dessen Struktur zum einen eine Kopie der Xwindow Struktur aber |
||||
|
auch noch weitere Informationen incl. Informationen für andere event typen |
||||
|
enthält. Diese Struktur kann dann mit den XWindow Methoden einen |
||||
|
X11_event_sink anlegen, aber auch einen neue Methode bauen die eine |
||||
|
andere event_sink erzeugt. Dadurch kann das neue Objekt dann auf beide |
||||
|
Arten Events reagieren. |
||||
|
|
||||
|
|
||||
|
scot_event_typ.c: |
||||
|
----------------- |
||||
|
Stellt die Struktur scot_event_typ bereit, welche voraussichtlich so aussieht: |
||||
|
|
||||
|
typedef struct scot_event_typ_st |
||||
|
{ |
||||
|
int id; /* diese wird von scot_event_typ_register gefüllt. */ |
||||
|
char * name; /* this is a unique name for the event_typ */ |
||||
|
|
||||
|
/* eine Struktur die für jeden event_typ anders aussieht, z.B. muß |
||||
|
für X events mindestens das Display bekannt sein. */ |
||||
|
void * event_typ_info; |
||||
|
|
||||
|
/* |
||||
|
* folgende Funktionen sind allen event Typen gemein, sie müssen nur |
||||
|
* für jeden event_typ unterschiedlich implementiert werden. |
||||
|
* Diese Implementierungen stehen dann in scot_event_type_*.[ch] |
||||
|
*/ |
||||
|
void (process_events*) (scot_dispatcher_st * dispatcher); |
||||
|
void (trigger_event*) (int event, |
||||
|
const void* event_sink, |
||||
|
const void* event_data); |
||||
|
}; |
||||
|
|
||||
|
außerdem wird eine globale statische Liste von registrierten event Typen |
||||
|
angelegt. (evtl. aber auch nicht, nämlich dann wenn ich einen Manger für |
||||
|
die event_types baue...dann enthält natürlich der manager die Liste.) |
||||
|
|
||||
|
GEN_LIST (scot_event_typ_st); |
||||
|
list_scot_event_typ_st_node_t * scot_registered_event_types; |
||||
|
|
||||
|
und folgende Funktionen: |
||||
|
void scot_event_typ_register (const scot_event_typ_st *event_typ); |
||||
|
void scot_event_typ_unregister (const scot_event_typ_st *event_typ); |
||||
|
scot_event_typ_st * scot_get_event_typ_by_name (const char * name); |
||||
|
|
||||
|
|
||||
|
scot_event_sink.c: |
||||
|
------------------ |
||||
|
Stellt die Struktur scot_event_sink bereit. Diese sieht voraussichtlich |
||||
|
irgendwie so aus: |
||||
|
|
||||
|
struct scot_event_sink |
||||
|
{ |
||||
|
struct scot_event_typ * event_typ; |
||||
|
/* |
||||
|
void (process_events*) (void); |
||||
|
void (trigger_event*) (int event, |
||||
|
const void* event_sink, |
||||
|
const void* data); |
||||
|
*/ |
||||
|
void * objekt; |
||||
|
}; |
||||
@ -0,0 +1,3 @@ |
|||||
|
#include <scot_event_sink.h> |
||||
|
|
||||
|
s |
||||
@ -0,0 +1,868 @@ |
|||||
|
/** |
||||
|
* \file exception.c |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief The core of the exception system implemented within libscot. |
||||
|
* |
||||
|
* This file has all implementations for the exception system of scot. |
||||
|
* It defines the exception_t structure which holds basic information |
||||
|
* about an exception. Instances of this structure are organized |
||||
|
* in a queue that is part of excenv_t. That stucture describes the environment |
||||
|
* in which exceptions may occure, that is a TRY-CATCH block. |
||||
|
* Every TRY creates a new excenv_t instance and puts them in a stack, |
||||
|
* every CATCH get one excenv_t from that stack. |
||||
|
* To achive threadsaveness those excenv_t stack is organized within |
||||
|
* thread_excenv_t which associates a thread-id to an excenv_t stack. |
||||
|
* Thus every stack has its own exception stack. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <errno.h> |
||||
|
#include <setjmp.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief We need direct access to elements of struct excenv_t. |
||||
|
*/ |
||||
|
#define USE_SCOT_STRUCT_EXCENV_T |
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief We need direct access to elements of struct exception_t. |
||||
|
*/ |
||||
|
#define USE_SCOT_STRUCT_EXCEPTION_T |
||||
|
#include <scot/exception.h> |
||||
|
#undef USE_SCOT_STRUCT_EXCENV_T |
||||
|
#undef USE_SCOT_STRUCT_EXCEPTION_T |
||||
|
|
||||
|
#include <scot/thread.h> /* for SELF_THREAD and THREAD_T macro */ |
||||
|
#include <scot/memory.h> /* for windows threadsafe memory functions */ |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief Don't use exceptions in the list code. |
||||
|
* |
||||
|
* as the code here provides the exception system it is not very wise to |
||||
|
* use exceptions in this code, Thus this define deactivates exception |
||||
|
* support within the code generation macros defined in \link scot/list.h |
||||
|
* scot/list.h\endlink. |
||||
|
*/ |
||||
|
#define USE_NO_EXCEPTION |
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief make list functions static for this file. |
||||
|
* |
||||
|
* All list, stack and queue stuff for exception structures is only needed |
||||
|
* here and not very likely to be needed anywhere else in the code. |
||||
|
* Thus generate them static, (said with GEN_LOCAL) |
||||
|
*/ |
||||
|
#define GEN_LOCAL |
||||
|
#include <scot/list.h> |
||||
|
#include <scot/stack.h> |
||||
|
#include <scot/queue.h> |
||||
|
#undef GEN_LOCAL |
||||
|
#undef USE_NO_EXCEPTION |
||||
|
|
||||
|
#include <scot_common.h> |
||||
|
|
||||
|
/************************************************************************ |
||||
|
* Generation of typesafe functions to handle lists of the types * |
||||
|
************************************************************************/ |
||||
|
GEN_LIST (exception_t); |
||||
|
GEN_QUEUE_FUNC_PROTO (exception_t); |
||||
|
GEN_QUEUE_IMPL (exception_t); |
||||
|
GEN_LIST (excenv_t); |
||||
|
GEN_STACK (excenv_t); |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* Structure to assign every thread an own exception environment stack. |
||||
|
*/ |
||||
|
struct thread_excenv_t |
||||
|
{ |
||||
|
THREAD_T thread_handle; /**< Current thread-id */ |
||||
|
stack_excenv_t_node_t *ee_stack; /**< The exception environment stack */ |
||||
|
}; |
||||
|
typedef struct thread_excenv_t thread_excenv_t; |
||||
|
GEN_LIST (thread_excenv_t); |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief If we use threads this is the root of all exception environments. |
||||
|
*/ |
||||
|
list_thread_excenv_t_node_t *tee_list = NULL; |
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief If we don't use threads this is the root of all exception |
||||
|
* environments. |
||||
|
*/ |
||||
|
stack_excenv_t_node_t *ee_stack = NULL; |
||||
|
|
||||
|
/************************************************************************ |
||||
|
* static helper * |
||||
|
************************************************************************/ |
||||
|
/** |
||||
|
* \internal |
||||
|
* \param a instance to be compared |
||||
|
* \param b instance to be compared |
||||
|
* \pre None |
||||
|
* \return A value greater than, equal or less than 0 as with strcmp. |
||||
|
* \retval <0 if a->thread_handle is less than b->thread_handle |
||||
|
* \retval >0 if a->thread_handle is greater than b->thread_handle |
||||
|
* \retval ==0 if a->thread_handle is equal to b->thread_handle |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Comparison for instances of thread_excenv_t. |
||||
|
* |
||||
|
* This is a comparison function for instances of thread_excenv_t. They are |
||||
|
* assumed equal if both thread_excenv_t::thread_handle are equal. |
||||
|
* The function follows the same scheme as for example strcmp. |
||||
|
*/ |
||||
|
static |
||||
|
int |
||||
|
compare_thread_excenv_t (const thread_excenv_t *a , const thread_excenv_t *b) |
||||
|
{ |
||||
|
return ! THREAD_EQUAL (*(THREAD_T *) a, *(THREAD_T *) b); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param e an instance of thread_excenv_t |
||||
|
* \pre \a e has to be initialize correctly previous to this call. |
||||
|
* \return Nothing |
||||
|
* \post The memory needed by \a e is correctly freed. |
||||
|
* |
||||
|
* \brief Destructor for thread_excenv_t instances. |
||||
|
* |
||||
|
* This cleanly frees an instance of thread_excenv_t. |
||||
|
*/ |
||||
|
static |
||||
|
void |
||||
|
free_thread_excenv_t (thread_excenv_t *e) |
||||
|
{ |
||||
|
stack_excenv_t_free (e->ee_stack); |
||||
|
SCOT_MEM_FREE (e); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param e an instance of excenv_t |
||||
|
* \pre \a e has to be initialize correctly previous to this call. |
||||
|
* \return Nothing |
||||
|
* \post The memory needed by \a e is correctly freed. |
||||
|
* |
||||
|
* \brief Destructor for excenv_t instances. |
||||
|
* |
||||
|
* This cleanly frees an instance of excenv_t. |
||||
|
*/ |
||||
|
static |
||||
|
void |
||||
|
free_excenv_t (excenv_t *e) |
||||
|
{ |
||||
|
queue_exception_t_free (e->e_queue); |
||||
|
SCOT_MEM_FREE (e); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param e an instance of exception_t |
||||
|
* \pre \a e has to be initialize correctly previous to this call. |
||||
|
* \return Nothing |
||||
|
* \post The memory needed by \a e is correctly freed. |
||||
|
* |
||||
|
* \brief Destructor for exception_t instances. |
||||
|
* |
||||
|
* This cleanly frees an instance of exception_t. |
||||
|
*/ |
||||
|
static |
||||
|
void |
||||
|
free_exception_t (exception_t * e) |
||||
|
{ |
||||
|
SCOT_MEM_FREE (e); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
/************************************************************************ |
||||
|
* interface implementtaion * |
||||
|
************************************************************************/ |
||||
|
/** |
||||
|
* \internal |
||||
|
* \pre No threads are used. |
||||
|
* \return Nothing |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief initializes the root of all exception environments for non |
||||
|
* threaded code. |
||||
|
* |
||||
|
* This is called within the TRY, CATCH macros to ensure that the correct |
||||
|
* exception environment stack for the current thread is used. |
||||
|
* \nWell, we don't have threads when this is used, so it just returns |
||||
|
* ee_stack if it has initialized it previously. |
||||
|
*/ |
||||
|
void * |
||||
|
exc_init (void) |
||||
|
{ |
||||
|
/* |
||||
|
* If threads are used already, use them further on. |
||||
|
* (If there is a threaded_exception list tee_list). |
||||
|
*/ |
||||
|
if (tee_list != NULL) |
||||
|
return threaded_exc_init (); |
||||
|
|
||||
|
if (ee_stack != NULL) |
||||
|
return (void *) ee_stack; |
||||
|
|
||||
|
ee_stack = stack_excenv_t_new (ee_stack); |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
if (ee_stack == NULL) |
||||
|
/* FIXME: make output to syslog or something... */ |
||||
|
{ |
||||
|
char buf[1024]; |
||||
|
|
||||
|
sprintf ( |
||||
|
buf, |
||||
|
"[Fatal(exception.c:97)]\n%s", |
||||
|
D_("exc_init failed")); |
||||
|
perror (buf); |
||||
|
abort (); |
||||
|
} |
||||
|
|
||||
|
return (void *) ee_stack; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \pre Threads are used. |
||||
|
* \return Nothing |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief initializes the root of all exception environments for non |
||||
|
* threaded code. |
||||
|
* |
||||
|
* This is called within the TRY, CATCH macros to ensure that the correct |
||||
|
* exception environment stack for the current thread is used. |
||||
|
*/ |
||||
|
void * |
||||
|
threaded_exc_init (void) |
||||
|
{ |
||||
|
list_thread_excenv_t_node_t *tee_l; |
||||
|
thread_excenv_t *tee; |
||||
|
THREAD_T t; |
||||
|
|
||||
|
t = SELF_THREAD; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
/* |
||||
|
* First create the list if it does not exist at all and |
||||
|
* set the comparison function. |
||||
|
*/ |
||||
|
if (tee_list == NULL) |
||||
|
{ |
||||
|
tee_list = list_thread_excenv_t_new (tee_list); |
||||
|
list_thread_excenv_t_set_cmp (compare_thread_excenv_t); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Now a little trick: As i compare thread_excenv_t by comparing its |
||||
|
* first element thread_excenv_t->thread_handle and don't use any other part of |
||||
|
* this struct with a compare i can cast THREAD_T * to thread_excenv_t * |
||||
|
* to check for the existance of an entry in the list. |
||||
|
*/ |
||||
|
tee_l = list_thread_excenv_t_find (tee_list, (thread_excenv_t *) &t); |
||||
|
|
||||
|
/* |
||||
|
* if tee_l != NULL we have found a previosly initialized stack, good! |
||||
|
* Return the excenv_t we have to use. |
||||
|
*/ |
||||
|
if (tee_l != NULL) |
||||
|
return (void *) list_thread_excenv_t_retrive (tee_l)->ee_stack; |
||||
|
|
||||
|
/* |
||||
|
* else we must create a new entry. |
||||
|
*/ |
||||
|
tee = (thread_excenv_t *) SCOT_MEM_GET (sizeof (struct thread_excenv_t)); |
||||
|
if (tee == NULL) |
||||
|
{ |
||||
|
char buf[1024]; |
||||
|
|
||||
|
sprintf ( |
||||
|
buf, |
||||
|
"[Fatal(exception.c:97)]\n%s", |
||||
|
D_("exc_init failed, can't get memory for new list element.")); |
||||
|
perror (buf); |
||||
|
abort (); |
||||
|
} |
||||
|
|
||||
|
tee->thread_handle = SELF_THREAD; |
||||
|
tee->ee_stack = stack_excenv_t_new (tee->ee_stack); |
||||
|
|
||||
|
if (tee->ee_stack == NULL) |
||||
|
/* FIXME: make output to syslog or something... */ |
||||
|
{ |
||||
|
char buf[1024]; |
||||
|
|
||||
|
sprintf ( |
||||
|
buf, |
||||
|
"[Fatal(exception.c:97)]\n%s", |
||||
|
D_("exc_init failed")); |
||||
|
perror (buf); |
||||
|
abort (); |
||||
|
} |
||||
|
|
||||
|
list_thread_excenv_t_insert (tee_list, tee); |
||||
|
|
||||
|
return (void *) tee->ee_stack; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param ee_s the stack of exception environments for the actual |
||||
|
* thread. |
||||
|
* \pre The root of the exception environments must be initialized |
||||
|
* either by exc_init() (if no threads are used) or by |
||||
|
* threaded_exc_init() (if threads are used). |
||||
|
* \return Nothing |
||||
|
* \post A new exception environment is pushed int the stack of exception |
||||
|
* environment (previously called root sometimes) and thus became |
||||
|
* current. |
||||
|
* |
||||
|
* \brief creates a new exception environment and pushes it into the root. |
||||
|
*/ |
||||
|
void |
||||
|
excenv_new (void *ee_s) |
||||
|
{ |
||||
|
stack_excenv_t_node_t *ee_stack = (stack_excenv_t_node_t *) ee_s; |
||||
|
excenv_t *ee; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
ee = (excenv_t *) SCOT_MEM_GET (sizeof (excenv_t)); |
||||
|
if (ee == NULL) |
||||
|
/* FIXME: make output to syslog or something... */ |
||||
|
{ |
||||
|
char buf[1024]; |
||||
|
|
||||
|
sprintf ( |
||||
|
buf, |
||||
|
"[Fatal(exception.c:113)]\n%s", |
||||
|
D_("excenv_new failed")); |
||||
|
perror (buf); |
||||
|
abort (); |
||||
|
} |
||||
|
|
||||
|
ee->e_queue = queue_exception_t_new (ee->e_queue); |
||||
|
if (ee->e_queue == NULL) |
||||
|
/* FIXME: make output to syslog or something... */ |
||||
|
{ |
||||
|
char buf[1024]; |
||||
|
|
||||
|
sprintf ( |
||||
|
buf, |
||||
|
"[Fatal(exception.c:121)]\n%s", |
||||
|
D_("excenv_new failed")); |
||||
|
perror (buf); |
||||
|
abort (); |
||||
|
} |
||||
|
|
||||
|
if (stack_excenv_t_push (ee_stack, ee) == NULL) |
||||
|
{ |
||||
|
char *errmsg; |
||||
|
char buf[1024]; |
||||
|
|
||||
|
errmsg = strerror (errno); |
||||
|
|
||||
|
stack_excenv_t_free (ee_stack); |
||||
|
SCOT_MEM_FREE (ee); |
||||
|
|
||||
|
sprintf ( |
||||
|
buf, |
||||
|
"[FATAL(exception.c:101)]\n%s%s", |
||||
|
D_("could not push the new excenv_t " |
||||
|
"into ee_stack:\n"), |
||||
|
errmsg); |
||||
|
|
||||
|
fprintf (stderr, buf); |
||||
|
|
||||
|
abort (); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param ee_s the stack of exception environments for the actual |
||||
|
* thread. |
||||
|
* \pre The root of the exception environments must be initialized |
||||
|
* either by exc_init() (if no threads are used) or by |
||||
|
* threaded_exc_init() (if threads are used). |
||||
|
* There must be an actual exception environment into the stack |
||||
|
* of exception environments. |
||||
|
* \return a pointer to the jmp_buf variable of the current exception |
||||
|
* environment. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief This returns a pointer to the jmp_buf variable of the current |
||||
|
* exception environment. |
||||
|
* |
||||
|
* A pointer to the jmp_buf variable of the current exception environment is |
||||
|
* returned for use by the setjmp call in TRY. I tried to call setjmp directly |
||||
|
* here, but that causes confusion when TRY-CATCH blocks are nested. |
||||
|
*/ |
||||
|
jmp_buf * |
||||
|
excenv_jmp_buf (void *ee_s) |
||||
|
{ |
||||
|
stack_excenv_t_node_t *ee_stack = (stack_excenv_t_node_t *) ee_s; |
||||
|
excenv_t *ee; |
||||
|
|
||||
|
ee = stack_excenv_t_top (ee_stack); |
||||
|
if (ee == NULL) |
||||
|
{ |
||||
|
fprintf ( |
||||
|
stderr, |
||||
|
D_("invalid exception environment\n")); |
||||
|
|
||||
|
abort (); |
||||
|
} |
||||
|
|
||||
|
return & (ee->env); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param ee_s the stack of exception environments for the actual |
||||
|
* thread. |
||||
|
* \param e the exception to be thrown. |
||||
|
* \pre The root of the exception environments must be initialized |
||||
|
* either by exc_init() (if no threads are used) or by |
||||
|
* threaded_exc_init() (if threads are used). |
||||
|
* There must be an actual exception environment into the stack |
||||
|
* of exception environments. |
||||
|
* \return Nothing |
||||
|
* \post A new exception is stored within the actual exception environment. |
||||
|
* |
||||
|
* \brief The implementation of the THROW macro. |
||||
|
* |
||||
|
* This stores a new exception within the actual exception environment. |
||||
|
*/ |
||||
|
void |
||||
|
exc_throw (void *ee_s, const exception_t *e) |
||||
|
{ |
||||
|
stack_excenv_t_node_t *ee_stack = (stack_excenv_t_node_t *) ee_s; |
||||
|
excenv_t *ee; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
/* get the actual excenv */ |
||||
|
ee = stack_excenv_t_top (ee_stack); |
||||
|
if (ee == NULL) |
||||
|
{ |
||||
|
char buf[1024]; |
||||
|
|
||||
|
sprintf ( |
||||
|
buf, |
||||
|
D_("any code that THROWs exeptions has to be\n" |
||||
|
"%s within a TRY block\n"), |
||||
|
" "); |
||||
|
|
||||
|
fprintf ( |
||||
|
stderr, |
||||
|
"[Fatal(exception.c:200)]\n%s", |
||||
|
buf); |
||||
|
|
||||
|
abort (); |
||||
|
} |
||||
|
|
||||
|
queue_exception_t_enqueue (ee->e_queue, e); |
||||
|
|
||||
|
if (e->lvl == EXC_ERROR && e->was_catched == 0) |
||||
|
longjmp (ee->env, 1); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param ee_s the stack of exception environments for the actual |
||||
|
* thread. |
||||
|
* \pre The root of the exception environments must be initialized |
||||
|
* either by exc_init() (if no threads are used) or by |
||||
|
* threaded_exc_init() (if threads are used). |
||||
|
* There must be an actual exception environment into the stack |
||||
|
* of exception environments. |
||||
|
* \return The current exception environment. |
||||
|
* \post The current exception environment is removed from the stack, thus |
||||
|
* making the next one on the stack to the current exception |
||||
|
* environment. |
||||
|
* |
||||
|
* \brief Get the current exception environment. |
||||
|
* |
||||
|
* The is the core of the CATCH() macro. It retrieves the actual exception |
||||
|
* environment from the stack of exception environments and returns it. The |
||||
|
* actual exception environment is removed from the stack. |
||||
|
*/ |
||||
|
excenv_t * |
||||
|
excenv_catch (void *ee_s) |
||||
|
{ |
||||
|
stack_excenv_t_node_t *ee_stack = (stack_excenv_t_node_t *) ee_s; |
||||
|
excenv_t *ee; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
ee = stack_excenv_t_pop (ee_stack); |
||||
|
if (ee == NULL) |
||||
|
{ |
||||
|
char buf[1024]; |
||||
|
|
||||
|
sprintf ( |
||||
|
buf, |
||||
|
"[Fatal(exception.c:177)]\n%s", |
||||
|
D_("use of CATCH with no previous TRY")); |
||||
|
perror (buf); |
||||
|
abort (); |
||||
|
} |
||||
|
|
||||
|
return ee; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \param ee The exception environment to be checked. |
||||
|
* \pre \a ee must be a valid exception environment. |
||||
|
* \return Boolean wether \a ee has exceptions or not. |
||||
|
* \retval ==0 there are no exceptions |
||||
|
* \retval !=0 there are exceptions |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Check for existent exceptions. |
||||
|
* |
||||
|
* This checks the given exception environment \a ee for existent |
||||
|
* exceptions. |
||||
|
*/ |
||||
|
int |
||||
|
excenv_has_exception (const excenv_t *ee) |
||||
|
{ |
||||
|
return ! list_exception_t_isempty ( |
||||
|
(list_exception_t_node_t *)ee->e_queue); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \param lvl either ERROR or WARNING |
||||
|
* \param file the file where the exception was created. |
||||
|
* \param line the line in that file. |
||||
|
* \param errnum an identifier of the exception. This might be |
||||
|
* dublicated as it is normally just used as an |
||||
|
* index for the error message. So rely only on this |
||||
|
* if you check only a special kind of error. |
||||
|
* \param err_msg a string describing what happens. |
||||
|
* \pre None |
||||
|
* \return The newly created exception. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Creates a new exception. |
||||
|
* |
||||
|
* This creates a new exception. Normally this function is called |
||||
|
* through the EXC() macro which fills in file and line automatically |
||||
|
* by using __FILE__ and __LINE__ but sometimes it is desirable to |
||||
|
* have direct control over those to values too. (For example with |
||||
|
* the templates of list functions.) |
||||
|
*/ |
||||
|
exception_t * |
||||
|
exc_new ( |
||||
|
const enum exclvl_t lvl, |
||||
|
const char *file, |
||||
|
const int line, |
||||
|
const int errnum, |
||||
|
const char *err_msg) |
||||
|
{ |
||||
|
exception_t *e; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
e = (exception_t *) SCOT_MEM_GET (sizeof (exception_t)); |
||||
|
if (e == NULL) |
||||
|
/* FIXME: make output to syslog or something... */ |
||||
|
{ |
||||
|
char buf[1024]; |
||||
|
|
||||
|
sprintf ( |
||||
|
buf, |
||||
|
"[Fatal(exception.c:220)]\n%s", |
||||
|
D_("exc_new failed")); |
||||
|
perror (buf); |
||||
|
abort (); |
||||
|
} |
||||
|
|
||||
|
/* This one time we write to lvl and id */ |
||||
|
e->was_catched = 0; |
||||
|
* (enum exclvl_t *) & e->lvl = lvl; |
||||
|
e->file = file; |
||||
|
* (int *) & e->line = line; |
||||
|
* (int *) & e->errnum = errnum; |
||||
|
e->err_msg = err_msg; |
||||
|
|
||||
|
return e; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \param ee The exception environment to be used. |
||||
|
* \pre \a ee must be a valid exception environment. |
||||
|
* \return The dequeued exception. |
||||
|
* \post The exception is removed from \a ee. |
||||
|
* |
||||
|
* \brief Get the actual exception. |
||||
|
* |
||||
|
* This dequeues the the next exception from the exception environment and |
||||
|
* returns it. |
||||
|
*/ |
||||
|
exception_t * |
||||
|
retrive_exception (const excenv_t *ee) |
||||
|
{ |
||||
|
exception_t *e; |
||||
|
|
||||
|
e = queue_exception_t_dequeue (ee->e_queue); |
||||
|
if (e != NULL) |
||||
|
e->was_catched += 1; |
||||
|
|
||||
|
return e; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \param ee The exception environment to be used. |
||||
|
* \pre Must be in a CATCH Block. So the exception environment is already |
||||
|
* removed from the stack of exception environments and only |
||||
|
* accessed by \a ee. |
||||
|
* \return Nothing |
||||
|
* \post All memory accessed over \a ee is freed, this includes all |
||||
|
* exceptions within it. |
||||
|
* |
||||
|
* \brief Frees the actually catched exception environment. |
||||
|
*/ |
||||
|
void free_catched (excenv_t *ee) |
||||
|
{ |
||||
|
free_excenv_t (ee); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \param e The exception to be used. |
||||
|
* \pre It is desirable to remove the exception first from the |
||||
|
* exception stack it is in, to keep from problems. |
||||
|
* \return Nothing |
||||
|
* \post All memory accessed over \a e is freed. |
||||
|
* |
||||
|
* \brief Frees an exception. |
||||
|
*/ |
||||
|
void |
||||
|
free_exception (exception_t *e) |
||||
|
{ |
||||
|
free_exception_t (e); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \pre None |
||||
|
* \return Nothing |
||||
|
* \post all memory allocated for any exception handling in the current |
||||
|
* thread is feed. |
||||
|
* |
||||
|
* \brief Ends exception handling for the actual thread. |
||||
|
* |
||||
|
* This should be called before ending a thread to avoid memory leaks. |
||||
|
*/ |
||||
|
void |
||||
|
exc_end (void) |
||||
|
{ |
||||
|
excenv_t *ee; |
||||
|
|
||||
|
list_exception_t_set_elem_free (free_exception_t); |
||||
|
list_excenv_t_set_elem_free (free_excenv_t); |
||||
|
|
||||
|
if (tee_list == NULL) |
||||
|
{ |
||||
|
stack_excenv_t_free (ee_stack); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
thread_exc_end (SELF_THREAD); |
||||
|
} |
||||
|
|
||||
|
list_exception_t_set_elem_free (NULL); |
||||
|
list_excenv_t_set_elem_free (NULL); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
thread_exc_end (THREAD_T t) |
||||
|
{ |
||||
|
list_thread_excenv_t_node_t *tee_l; |
||||
|
|
||||
|
list_exception_t_set_elem_free (free_exception_t); |
||||
|
list_excenv_t_set_elem_free (free_excenv_t); |
||||
|
list_thread_excenv_t_set_elem_free (free_thread_excenv_t); |
||||
|
|
||||
|
tee_l = list_thread_excenv_t_find (tee_list, (thread_excenv_t *) &t); |
||||
|
|
||||
|
list_thread_excenv_t_delete (tee_l); |
||||
|
|
||||
|
/* |
||||
|
* well, maybe this has to have some syncronization with |
||||
|
* threaded_exc_init or i make a function exc_fini, that |
||||
|
* does this final step and should only be called in the |
||||
|
* main thread. |
||||
|
*/ |
||||
|
if (list_thread_excenv_t_isempty (tee_list)) |
||||
|
list_thread_excenv_t_free (tee_list); |
||||
|
|
||||
|
list_thread_excenv_t_set_elem_free (NULL); |
||||
|
list_exception_t_set_elem_free (NULL); |
||||
|
list_excenv_t_set_elem_free (NULL); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \pre \a e must be a valid exception. |
||||
|
* \return Nothing |
||||
|
* \post \a e is freed. |
||||
|
* |
||||
|
* \brief Prints out the exception and frees it after that. |
||||
|
*/ |
||||
|
void |
||||
|
print_exception (exception_t * e) |
||||
|
{ |
||||
|
fprintf ( |
||||
|
stderr, |
||||
|
"[%s(%s:%d)]\n(%d) %s\n", |
||||
|
(e->lvl==EXC_ERROR)?D_("ERROR"):D_("WARNING"), |
||||
|
e->file, |
||||
|
e->line, |
||||
|
e->errnum, |
||||
|
e->err_msg); |
||||
|
|
||||
|
/* no more free at print...this is not intuitive usable. */ |
||||
|
/* free_exception (e); */ |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \pre \a ee must be a valid exception environment. |
||||
|
* \return Nothing |
||||
|
* \post \a ee is freed. |
||||
|
* |
||||
|
* \brief Prints out all exceptions and frees them after that. |
||||
|
* |
||||
|
* This prints out all exception one by one using print_exception() |
||||
|
* and after that frees also the exception environment \a ee. |
||||
|
*/ |
||||
|
void |
||||
|
print_all_exceptions (excenv_t *ee) |
||||
|
{ |
||||
|
exception_t *e; |
||||
|
|
||||
|
e = retrive_exception (ee); |
||||
|
while (e != NULL) |
||||
|
{ |
||||
|
print_exception (e); |
||||
|
e = retrive_exception (ee); |
||||
|
} |
||||
|
|
||||
|
free_catched (ee); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \param ee the exception environment to be used. |
||||
|
* \pre \a ee must be a valid exception environment.\n |
||||
|
* There must be at least one exception environment left in the |
||||
|
* stack of exception environments. |
||||
|
* \return Nothing |
||||
|
* \post All exception within \a ee are in the actual exception environment. |
||||
|
* |
||||
|
* \brief Forwards all exceptions in \a ee to the actual |
||||
|
* exception environment. |
||||
|
* |
||||
|
* This did not free any exception but throw the from \a ee into the |
||||
|
* actual exception environment. |
||||
|
*/ |
||||
|
void |
||||
|
forward_all_exceptions (excenv_t *ee) |
||||
|
{ |
||||
|
exception_t *e; |
||||
|
excenv_t *_ee; |
||||
|
|
||||
|
if (tee_list != NULL) |
||||
|
/* we use threads */ |
||||
|
_ee = threaded_exc_init (); |
||||
|
else |
||||
|
/* we don't use threads */ |
||||
|
_ee = exc_init (); |
||||
|
|
||||
|
e = retrive_exception (ee); |
||||
|
while (e != NULL) |
||||
|
{ |
||||
|
exc_throw (_ee, e); |
||||
|
e = retrive_exception (ee); |
||||
|
} |
||||
|
|
||||
|
free_catched (ee); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \param e the exception to be checked. |
||||
|
* \pre \a e must be a valid exception. |
||||
|
* \return Boolean indicating if the exception was thrown within the |
||||
|
* actual exception environment or just be forwarded from another one. |
||||
|
* \retval ==0 the exception was forwarded. |
||||
|
* \retval !=0 the exception was thrown. |
||||
|
* \post None |
||||
|
* |
||||
|
* \brief Checks wether \a e was thrown or forwarded. |
||||
|
*/ |
||||
|
int |
||||
|
exc_in_this_try (exception_t *e) |
||||
|
{ |
||||
|
return e->was_catched == 1; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/************************************************************************ |
||||
|
* exception getter * |
||||
|
************************************************************************/ |
||||
|
enum exclvl_t |
||||
|
exc_lvl_get (exception_t *e) |
||||
|
{ |
||||
|
return e->lvl; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
exc_errnum_get (exception_t *e) |
||||
|
{ |
||||
|
return e->errnum; |
||||
|
} |
||||
|
|
||||
|
char * |
||||
|
exc_err_msg_get (exception_t *e) |
||||
|
{ |
||||
|
return (char *) e->err_msg; |
||||
|
} |
||||
|
|
||||
|
char * |
||||
|
exc_file_get (exception_t *e) |
||||
|
{ |
||||
|
return (char *) e->file; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
exc_line_get (exception_t *e) |
||||
|
{ |
||||
|
return e->line; |
||||
|
} |
||||
@ -0,0 +1,416 @@ |
|||||
|
#include <sys/select.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <unistd.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
#include <scot/inotify.h> |
||||
|
#include <scot/fs_watcher.h> |
||||
|
#include <scot/event_listener.h> |
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/event.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot/thread.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
#define GEN_LOCAL |
||||
|
# include <scot/list.h> |
||||
|
#undef GEN_LOCAL |
||||
|
|
||||
|
GEN_LIST_FUNC_PROTO (scot_fsw_info); |
||||
|
GEN_LIST_IMPL (scot_fsw_info); |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
scot_fsw_info_free (scot_fsw_info * e) |
||||
|
{ |
||||
|
if (e != NULL) |
||||
|
{ |
||||
|
if (e->path != NULL) |
||||
|
SCOT_MEM_FREE (e->path); |
||||
|
if (e->old_name != NULL) |
||||
|
SCOT_MEM_FREE (e->old_name); |
||||
|
|
||||
|
SCOT_MEM_FREE (e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
scot_fsw_info_cmp_path (const scot_fsw_info * a, const scot_fsw_info * b) |
||||
|
{ |
||||
|
return strcmp (a->path, b->path); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
scot_fsw_info_cmp_watch_d (const scot_fsw_info * a, const scot_fsw_info * b) |
||||
|
{ |
||||
|
return (a->watch_d == b->watch_d)?0:(a->watch_d < b->watch_d)?-1:1; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static |
||||
|
void |
||||
|
thread_fini (void * arg) |
||||
|
{ |
||||
|
exc_end (); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
unsigned short |
||||
|
default_cb (struct scot_event * _e) |
||||
|
{ |
||||
|
SSIZE_T n; |
||||
|
char puffer[1024]; |
||||
|
struct scot_fs_watcher_event * e = (struct scot_fs_watcher_event *) _e; |
||||
|
|
||||
|
switch (_e->event) |
||||
|
{ |
||||
|
case (SCOT_EVENT_FS_WATCHER_CREATE): |
||||
|
printf ("%s/%s created\n", e->path, e->name); |
||||
|
break; |
||||
|
case (SCOT_EVENT_FS_WATCHER_DELETE): |
||||
|
printf ("%s/%s deleted\n", e->path, e->name); |
||||
|
break; |
||||
|
case (SCOT_EVENT_FS_WATCHER_RENAME): |
||||
|
printf ("%s/%s renamed to %s/%s\n", |
||||
|
e->path, e->oldname, |
||||
|
e->path, e->name); |
||||
|
break; |
||||
|
|
||||
|
/* more to come .... */ |
||||
|
|
||||
|
default: break; |
||||
|
} |
||||
|
|
||||
|
fflush (stdout); |
||||
|
|
||||
|
return SCOT_EVENT_END; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
struct scot_fs_watcher * |
||||
|
scot_fs_watcher_new (void) |
||||
|
{ |
||||
|
struct scot_fs_watcher * fsw; |
||||
|
|
||||
|
fsw = SCOT_MEM_GET (sizeof (struct scot_fs_watcher)); |
||||
|
SCOT_MEM_ZERO (fsw, sizeof (struct scot_fs_watcher)); |
||||
|
|
||||
|
fsw->w_list = list_scot_fsw_info_new (fsw->w_list); |
||||
|
|
||||
|
list_scot_fsw_info_set_elem_free (scot_fsw_info_free); |
||||
|
|
||||
|
SCOT_MEM_ZERO (&fsw->notify_d, sizeof (struct scot_stream)); |
||||
|
|
||||
|
fsw->notify_d.handle.file = inotify_init (); |
||||
|
if (fsw->notify_d.handle.file == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
|
||||
|
fsw->notify_d.s_type = SCOT_STREAM_TYPE_INOTIFY; |
||||
|
scot_stream_set_nonblock (&fsw->notify_d); |
||||
|
|
||||
|
FD_SET (fsw->notify_d.handle.file, &fsw->rfds); |
||||
|
|
||||
|
scot_event_listener_init ( |
||||
|
(struct scot_event_listener *) fsw, |
||||
|
SCOT_EG_FS_WATCHER, |
||||
|
(scot_thread_entry_fptr) scot_fs_watcher_main_loop); |
||||
|
|
||||
|
scot_event_listener_register_cb ( |
||||
|
(struct scot_event_listener *) fsw, |
||||
|
SCOT_EVENT_FS_WATCHER_CREATE, |
||||
|
default_cb, NULL); |
||||
|
scot_event_listener_register_cb ( |
||||
|
(struct scot_event_listener *) fsw, |
||||
|
SCOT_EVENT_FS_WATCHER_DELETE, |
||||
|
default_cb, NULL); |
||||
|
scot_event_listener_register_cb ( |
||||
|
(struct scot_event_listener *) fsw, |
||||
|
SCOT_EVENT_FS_WATCHER_RENAME, |
||||
|
default_cb, NULL); |
||||
|
|
||||
|
NEW_THREAD_MUTEX (&fsw->mutex); |
||||
|
|
||||
|
return fsw; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_fs_watcher_free (struct scot_fs_watcher * fsw) |
||||
|
{ |
||||
|
scot_event_listener_fini ((struct scot_event_listener *) fsw); |
||||
|
|
||||
|
list_scot_fsw_info_free (fsw->w_list); |
||||
|
|
||||
|
FREE_THREAD_MUTEX (&fsw->mutex); |
||||
|
|
||||
|
SCOT_MEM_FREE (fsw); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_fs_watcher_add ( |
||||
|
struct scot_fs_watcher * fsw, |
||||
|
const char * path, |
||||
|
uint32_t mask) |
||||
|
{ |
||||
|
struct scot_event_listener * l = (struct scot_event_listener *) fsw; |
||||
|
struct scot_fsw_info * fswi; |
||||
|
|
||||
|
/* |
||||
|
* soweit ich das in erinnerung habe sind meine listen nicht per se |
||||
|
* thread save. Daher sollte hier unbedingt noch ein mutex her, |
||||
|
* damit nicht gleichzeitig in die liste geschriebe (hier) |
||||
|
* und gelöscht wird (in remove) |
||||
|
*/ |
||||
|
LOCK_THREAD_MUTEX (&fsw->mutex); |
||||
|
|
||||
|
fswi = SCOT_MEM_GET (sizeof (struct scot_fsw_info)); |
||||
|
SCOT_MEM_ZERO (fswi, sizeof (struct scot_fsw_info)); |
||||
|
fswi->path = SCOT_MEM_GET (SCOT_STR_LENGTH (path) + 1); |
||||
|
SCOT_STR_COPY (fswi->path, path); |
||||
|
|
||||
|
if ((mask & SCOT_EVENT_FS_WATCHER_CREATE) == SCOT_EVENT_FS_WATCHER_CREATE) |
||||
|
fswi->mask |= IN_CREATE; |
||||
|
if ((mask & SCOT_EVENT_FS_WATCHER_DELETE) == SCOT_EVENT_FS_WATCHER_DELETE) |
||||
|
fswi->mask |= IN_DELETE; |
||||
|
if ((mask & SCOT_EVENT_FS_WATCHER_RENAME) == SCOT_EVENT_FS_WATCHER_RENAME) |
||||
|
fswi->mask |= IN_MOVED_FROM | IN_MOVED_TO; |
||||
|
|
||||
|
fswi->watch_d = inotify_add_watch (fsw->notify_d.handle.file, path, fswi->mask); |
||||
|
if (fswi->watch_d == -1) |
||||
|
{ |
||||
|
SCOT_MEM_FREE (fswi->path); |
||||
|
SCOT_MEM_FREE (fswi); |
||||
|
|
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
} |
||||
|
|
||||
|
list_scot_fsw_info_set_cmp (scot_fsw_info_cmp_path); |
||||
|
|
||||
|
if (list_scot_fsw_info_find (fsw->w_list, fswi) == NULL) |
||||
|
list_scot_fsw_info_insert (fsw->w_list, fswi); |
||||
|
|
||||
|
list_scot_fsw_info_set_cmp (list_scot_fsw_info_default_cmp); |
||||
|
|
||||
|
/* restart thread if running. */ |
||||
|
if (scot_event_listener_is_running (l) != 0 && l->thread_handle != THREAD_ID) |
||||
|
{ |
||||
|
scot_event_listener_stop (l); |
||||
|
scot_event_listener_start (l); |
||||
|
} |
||||
|
|
||||
|
UNLOCK_THREAD_MUTEX (&fsw->mutex); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_fs_watcher_remove ( |
||||
|
struct scot_fs_watcher * fsw, |
||||
|
const char * path, |
||||
|
uint32_t mask) |
||||
|
{ |
||||
|
struct scot_event_listener * l = (struct scot_event_listener *) fsw; |
||||
|
int was_running = scot_event_listener_is_running (l); |
||||
|
list_scot_fsw_info_node_t * node; |
||||
|
struct scot_fsw_info search_fswi = {0, (char *)path, 0, 0, NULL}; |
||||
|
struct scot_fsw_info * fswi; |
||||
|
|
||||
|
LOCK_THREAD_MUTEX (&fsw->mutex); |
||||
|
|
||||
|
if (was_running != 0 && l->thread_handle != THREAD_ID) |
||||
|
scot_event_listener_stop (l); |
||||
|
|
||||
|
list_scot_fsw_info_set_cmp (scot_fsw_info_cmp_path); |
||||
|
|
||||
|
node = list_scot_fsw_info_find (fsw->w_list, &search_fswi); |
||||
|
fswi = list_scot_fsw_info_retrive (node); |
||||
|
|
||||
|
list_scot_fsw_info_set_cmp (list_scot_fsw_info_default_cmp); |
||||
|
|
||||
|
if ((mask & SCOT_EVENT_FS_WATCHER_CREATE) == SCOT_EVENT_FS_WATCHER_CREATE) |
||||
|
fswi->mask &= ~IN_CREATE; |
||||
|
if ((mask & SCOT_EVENT_FS_WATCHER_DELETE) == SCOT_EVENT_FS_WATCHER_DELETE) |
||||
|
fswi->mask &= ~IN_DELETE; |
||||
|
if ((mask & SCOT_EVENT_FS_WATCHER_RENAME) == SCOT_EVENT_FS_WATCHER_RENAME) |
||||
|
fswi->mask &= ~IN_MOVED_FROM & ~IN_MOVED_TO; |
||||
|
|
||||
|
if (fswi->mask == 0) |
||||
|
{ |
||||
|
inotify_rm_watch (fsw->notify_d.handle.file, fswi->watch_d); |
||||
|
node = list_scot_fsw_info_delete (node); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
inotify_add_watch (fsw->notify_d.handle.file, fswi->path, fswi->mask); |
||||
|
node = list_scot_fsw_info_next (node); |
||||
|
} |
||||
|
|
||||
|
if (was_running != 0 && l->thread_handle != THREAD_ID) |
||||
|
scot_event_listener_start (l); |
||||
|
|
||||
|
UNLOCK_THREAD_MUTEX (&fsw->mutex); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static |
||||
|
struct inotify_event * |
||||
|
scot_fs_watcher_get_event (struct scot_fs_watcher * fsw) |
||||
|
{ |
||||
|
static int size = 0; |
||||
|
static int got = 0; |
||||
|
static char * buffer = NULL; |
||||
|
struct inotify_event * e = NULL; |
||||
|
|
||||
|
if (size == 0) |
||||
|
{ |
||||
|
got = 0; |
||||
|
size = 16; |
||||
|
size = sizeof (struct inotify_event); |
||||
|
buffer = SCOT_MEM_GET (size); |
||||
|
} |
||||
|
|
||||
|
got += scot_stream_read (&fsw->notify_d, buffer+got, size-got); |
||||
|
|
||||
|
if (size == got) |
||||
|
{ |
||||
|
if (size == sizeof (struct inotify_event)) |
||||
|
{ |
||||
|
char * tmp_buf = buffer; |
||||
|
|
||||
|
size += ((struct inotify_event *)buffer)->len; |
||||
|
buffer = SCOT_MEM_GET (size); |
||||
|
SCOT_MEM_COPY (buffer, tmp_buf, sizeof (struct inotify_event)); |
||||
|
SCOT_MEM_FREE (tmp_buf); |
||||
|
got += scot_stream_read (&fsw->notify_d, buffer+got, size-got); |
||||
|
} |
||||
|
|
||||
|
if (size == got) |
||||
|
{ |
||||
|
e = SCOT_MEM_GET (size); |
||||
|
SCOT_MEM_COPY (e, buffer, size); |
||||
|
SCOT_MEM_FREE (buffer); |
||||
|
size = 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return e; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* entry point für einen stream-pool event-source thread. |
||||
|
*/ |
||||
|
void |
||||
|
scot_fs_watcher_main_loop (struct scot_fs_watcher * fsw) |
||||
|
{ |
||||
|
fd_set run_rfds; |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
THREAD_CANCEL_ENABLE; |
||||
|
THREAD_CANCEL_DEFER; |
||||
|
|
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
THREAD_ATEXIT_BEGIN (thread_fini, NULL); |
||||
|
|
||||
|
while (1) |
||||
|
{ |
||||
|
struct inotify_event * ie = NULL; |
||||
|
|
||||
|
run_rfds = fsw->rfds; |
||||
|
|
||||
|
/* evtl. sollte man hier noch timeout support einbauen, sprich |
||||
|
* das letzte NULL mit einer time austauschen. */ |
||||
|
if (select (fsw->notify_d.handle.file+1, &run_rfds, NULL, NULL, NULL) == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
|
||||
|
while ((ie = scot_fs_watcher_get_event (fsw)) != NULL) |
||||
|
{ |
||||
|
struct scot_fsw_info sfswi = {ie->wd, NULL, 0, 0, NULL}; |
||||
|
struct scot_fsw_info * fswi; |
||||
|
struct scot_fs_watcher_event * e = NULL; |
||||
|
list_scot_fsw_info_node_t * w_node; |
||||
|
|
||||
|
SCOT_MEM_ZERO (&e, sizeof (struct scot_fs_watcher_event)); |
||||
|
|
||||
|
list_scot_fsw_info_set_cmp (scot_fsw_info_cmp_watch_d); |
||||
|
|
||||
|
w_node = list_scot_fsw_info_find (fsw->w_list, &sfswi); |
||||
|
fswi = list_scot_fsw_info_retrive (w_node); |
||||
|
|
||||
|
list_scot_fsw_info_set_cmp (list_scot_fsw_info_default_cmp); |
||||
|
|
||||
|
/* |
||||
|
* Ok, jetzt muß code folgen, der die got_events maske |
||||
|
* analysiert und je nachdem wie diese gesetzt ist |
||||
|
* ein scot event erzeugt oder nicht...soll heißen einen |
||||
|
* callback aufruft oder nicht. |
||||
|
*/ |
||||
|
if (ie->mask == IN_MOVED_FROM) |
||||
|
{ |
||||
|
struct inotify_event * _ie = scot_fs_watcher_get_event (fsw); |
||||
|
|
||||
|
if (_ie != NULL && |
||||
|
_ie->mask == IN_MOVED_TO && |
||||
|
ie->wd == _ie->wd) |
||||
|
{ |
||||
|
e = scot_fs_watcher_event_new ( |
||||
|
e, SCOT_EVENT_FS_WATCHER_RENAME, NULL, 0, |
||||
|
fswi->path, _ie->name, ie->name); |
||||
|
|
||||
|
if (_ie != NULL) |
||||
|
SCOT_MEM_FREE (_ie); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
e = scot_fs_watcher_event_new ( |
||||
|
e, SCOT_EVENT_FS_WATCHER_DELETE, NULL, 0, |
||||
|
fswi->path, ie->name, NULL); |
||||
|
|
||||
|
scot_event_listener_call_cb ( |
||||
|
(struct scot_event_listener *) fsw, |
||||
|
(struct scot_event *) e); |
||||
|
|
||||
|
scot_event_free ((struct scot_event *) e); |
||||
|
e = NULL; |
||||
|
|
||||
|
SCOT_MEM_FREE (ie); |
||||
|
ie = _ie; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (ie != NULL && (ie->mask & (IN_MOVED_TO | IN_CREATE)) != 0) |
||||
|
e = scot_fs_watcher_event_new ( |
||||
|
e, SCOT_EVENT_FS_WATCHER_CREATE, NULL, 0, |
||||
|
fswi->path, ie->name, NULL); |
||||
|
|
||||
|
if (ie != NULL && ie->mask ==IN_DELETE) |
||||
|
e = scot_fs_watcher_event_new ( |
||||
|
e, SCOT_EVENT_FS_WATCHER_DELETE, NULL, 0, |
||||
|
fswi->path, ie->name, NULL); |
||||
|
|
||||
|
if (e != NULL) |
||||
|
{ |
||||
|
/* call callback... */ |
||||
|
scot_event_listener_call_cb ( |
||||
|
(struct scot_event_listener *) fsw, |
||||
|
(struct scot_event *) e); |
||||
|
|
||||
|
/* free e after callback */ |
||||
|
scot_event_free ((struct scot_event *) e); |
||||
|
e = NULL; |
||||
|
} |
||||
|
|
||||
|
if (ie != NULL) |
||||
|
SCOT_MEM_FREE (ie); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
THREAD_ATEXIT_END (1); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
print_all_exceptions (ee); |
||||
|
exit (EXIT_FAILURE); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,340 @@ |
|||||
|
/** |
||||
|
* \file list.c |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Internal implementations for list handling. |
||||
|
* |
||||
|
* This implements the internals for the typesafe linked list |
||||
|
* implementation provided by \link scot/list.h list.h\endlink, |
||||
|
* \link scot/list_proto.h list_proto.h\endlink and |
||||
|
* \link scot/list_impl.h list_impl.h\endlink. |
||||
|
* The only thing one has to remember when one only wants to |
||||
|
* use linked lists within the own code is to link the code agains |
||||
|
* an object of this. This is normally done by linking agains |
||||
|
* libscot with an -lscot or similar compiler switch. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
#include <scot/list.h> |
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/scot_exceptions.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot_common.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief Error messages given. |
||||
|
* |
||||
|
* This holds all error messages that go either to the exception system |
||||
|
* or will be printed on stderr if an error occurs within a list function. |
||||
|
*/ |
||||
|
const char *list_err_msg[] = |
||||
|
{ |
||||
|
N_("[LIST]Failed to create new list."), |
||||
|
N_("[LIST]Failed to free list."), |
||||
|
N_("[LIST]Failed to check for begin of list."), |
||||
|
N_("[LIST]Failed to check for end of list."), |
||||
|
N_("[LIST]Failed to check for list emptiness."), |
||||
|
N_("[LIST]Failed to get first list node."), |
||||
|
N_("[LIST]Failed to get last list node."), |
||||
|
N_("[LIST]Failed to get next list node."), |
||||
|
N_("[LIST]Failed to get previous list node."), |
||||
|
N_("[LIST]Failed to find list node."), |
||||
|
N_("[LIST]Failed to find list anchor."), |
||||
|
N_("[LIST]Failed to retrive the node's value."), |
||||
|
N_("[LIST]Failed to set the node's value."), |
||||
|
N_("[LIST]Failed to insert node."), |
||||
|
N_("[LIST]Failed to delete node."), |
||||
|
N_("[LIST]Failed to concatanate the lists."), |
||||
|
N_("[LIST]Failed to count list nodes."), |
||||
|
N_("[LIST]Node is no anchor."), |
||||
|
N_("[LIST]Malformed list."), |
||||
|
NULL |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief Warning messages given. |
||||
|
* |
||||
|
* This holds all warning messages that go either to the exception system |
||||
|
* or will be printed on stderr if an error occurs within a list function. |
||||
|
*/ |
||||
|
const char *list_wrn_msg[] = |
||||
|
{ |
||||
|
N_("[LIST]tried to delete on an empyt list"), |
||||
|
NULL |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param lvl either ERROR or WARNING |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* \param id the error or warning id. (Used to pick the correct message) |
||||
|
* |
||||
|
* \pre None |
||||
|
* \returns Nothing |
||||
|
* \post An error or warning message printed to stderr. In case of an |
||||
|
* ERROR the program is aborted. |
||||
|
* |
||||
|
* \brief Print error or warning to stderr. |
||||
|
*/ |
||||
|
static |
||||
|
void |
||||
|
list_ew_print ( |
||||
|
const enum exclvl_t lvl, |
||||
|
const char *file, |
||||
|
const int line, |
||||
|
const int id) |
||||
|
{ |
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
fprintf ( |
||||
|
stderr, |
||||
|
"[%s(%s:%d)]\n(%d) %s\n", |
||||
|
(lvl == EXC_ERROR)?D_("ERROR"):D_("WARNING"), |
||||
|
file, |
||||
|
line, |
||||
|
id, |
||||
|
(lvl == EXC_ERROR)?D_(list_err_msg [id]):D_(list_wrn_msg [id])); |
||||
|
|
||||
|
if (lvl == EXC_ERROR) |
||||
|
{ |
||||
|
abort (); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param lvl either ERROR or WARNING |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* \param id the error or warning id. (Used to pick the correct message) |
||||
|
* |
||||
|
* \pre An exception environment created by a previous call of TRY. |
||||
|
* \returns Nothing |
||||
|
* \post An exception thrown into the exception environment. |
||||
|
* |
||||
|
* \brief Throw error or warning in an exception environment. |
||||
|
*/ |
||||
|
static |
||||
|
void |
||||
|
list_ew_throw ( |
||||
|
enum exclvl_t lvl, |
||||
|
const char *file, |
||||
|
int line, |
||||
|
int id) |
||||
|
{ |
||||
|
THROW (exc_new (lvl, file, line, id, D_(list_err_msg [id]))); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* \param id the error id. (Used to pick the correct message) |
||||
|
* |
||||
|
* \pre None |
||||
|
* \returns Nothing |
||||
|
* \post An error message printed to stderr. The program is aborted. |
||||
|
* |
||||
|
* \brief Print error to stderr. |
||||
|
*/ |
||||
|
void |
||||
|
list_error_print (const char *file, int line, const int id) |
||||
|
{ |
||||
|
list_ew_print (EXC_ERROR, file, line, id); |
||||
|
} |
||||
|
/** |
||||
|
* \internal |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* \param id the warning id. (Used to pick the correct message) |
||||
|
* |
||||
|
* \pre None |
||||
|
* \returns Nothing |
||||
|
* \post An warning message printed to stderr. |
||||
|
* |
||||
|
* \brief Print warning to stderr. |
||||
|
*/ |
||||
|
void |
||||
|
list_warning_print (const char *file, int line, int id) |
||||
|
{ |
||||
|
list_ew_print (EXC_WARNING, file, line, id); |
||||
|
} |
||||
|
/** |
||||
|
* \internal |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* \param id the error id. (Used to pick the correct message) |
||||
|
* |
||||
|
* \pre An exception environment created by a previous call of TRY. |
||||
|
* \returns Nothing |
||||
|
* \post An exception thrown into the exception environment. |
||||
|
* |
||||
|
* \brief Throw error. |
||||
|
*/ |
||||
|
void |
||||
|
list_error_throw (const char *file, int line, int id) |
||||
|
{ |
||||
|
list_ew_throw (EXC_ERROR, file, line, id); |
||||
|
} |
||||
|
void |
||||
|
/** |
||||
|
* \internal |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* \param id the warning id. (Used to pick the correct message) |
||||
|
* |
||||
|
* \pre An exception environment created by a previous call of TRY. |
||||
|
* \returns Nothing |
||||
|
* \post An exception thrown into the exception environment. |
||||
|
* |
||||
|
* \brief Throw warning. |
||||
|
*/ |
||||
|
list_warning_throw (const char *file, int line, int id) |
||||
|
{ |
||||
|
list_ew_throw (EXC_WARNING, file, line, id); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param size SIZE_T size of memory to be allocates (see man malloc). |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* |
||||
|
* \pre None |
||||
|
* \returns A pointer to the memory location reserved by malloc. |
||||
|
* \post Either memory is allocated on the heap or an error messege is |
||||
|
* printed to stderr and the program aborted. |
||||
|
* |
||||
|
* \brief Malloc wrapper with error handling. |
||||
|
* |
||||
|
* This calls malloc and if it fails gives an error message to stderr. |
||||
|
* If this malloc fails it is assumed a serious error and thus the program |
||||
|
* is aborted in this case. |
||||
|
*/ |
||||
|
void * |
||||
|
list_malloc_print (SIZE_T size, const char *file, int line) |
||||
|
{ |
||||
|
void *a; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
a = SCOT_MEM_GET (size); |
||||
|
|
||||
|
if (a == NULL) |
||||
|
{ |
||||
|
fprintf ( |
||||
|
stderr, |
||||
|
"[ERROR(%s:%d)]\n(%d) %s\n", |
||||
|
file, |
||||
|
line, |
||||
|
MALLOC_ERR, |
||||
|
D_(scot_err_msg [MALLOC_ERR])); |
||||
|
|
||||
|
abort (); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param size SIZE_T size of memory to be allocates (see man malloc). |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* |
||||
|
* \pre An exception environment created by a previous call of TRY. |
||||
|
* \returns A pointer to the memory location reserved by malloc. |
||||
|
* \post Either memory is allocated on the heap or an exception thrown |
||||
|
* into the exception environment. |
||||
|
* |
||||
|
* \brief Malloc wrapper with error handling. |
||||
|
* |
||||
|
* This calls malloc and if it fails throws an exception. |
||||
|
* This malloc fails it is assumed a serious error and thus an ERROR |
||||
|
* is thrown into the exception system causing the calling function to |
||||
|
* be aborted and goes to exception handling CATCH of the current |
||||
|
* exception environment. |
||||
|
*/ |
||||
|
void * |
||||
|
list_malloc_throw (SIZE_T size, const char *file, int line) |
||||
|
{ |
||||
|
return exc_malloc_fl (size, file, line); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param val Pointer to be checked. |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* |
||||
|
* \pre None |
||||
|
* \returns Nothing. |
||||
|
* \post If val is NULL an error messege is |
||||
|
* printed to stderr and the program aborted. |
||||
|
* |
||||
|
* \brief Checks the given value for beeing NULL. |
||||
|
* |
||||
|
* This checks the given \a val for beeing NULL and if is gives an |
||||
|
* error message to stderr. If this check fails within the list |
||||
|
* code it is a serious error and thus the program is aborted. |
||||
|
*/ |
||||
|
void |
||||
|
list_check_null_print (const void *val, const char *file, int line) |
||||
|
{ |
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
if (val == NULL) |
||||
|
{ |
||||
|
fprintf ( |
||||
|
stderr, |
||||
|
"[ERROR(%s:%d)]\n(%d) %s\n", |
||||
|
file, |
||||
|
line, |
||||
|
NULL_PTR_ERR, |
||||
|
D_(scot_err_msg [NULL_PTR_ERR])); |
||||
|
|
||||
|
abort (); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \param val Pointer to be checked. |
||||
|
* \param file the filename of the source file from where this is called |
||||
|
* \param line the line in the source file from where this is called |
||||
|
* |
||||
|
* \pre An exception environment created by a previous call of TRY. |
||||
|
* \returns Nothing. |
||||
|
* \post If val is NULL an exception thrown |
||||
|
* into the exception environment. |
||||
|
* |
||||
|
* \brief Checks the given value for beeing NULL. |
||||
|
* |
||||
|
* This checks the given \a val for beeing NULL and if is throws |
||||
|
* an exception. If this check fails within the list code it is a |
||||
|
* serious error and thus an ERROR is throw into the exception system, |
||||
|
* causing the calling function to abort and go to exception handling |
||||
|
* CATCH of the actual exception environment. |
||||
|
*/ |
||||
|
void |
||||
|
list_check_null_throw (const void *val, const char *file, int line) |
||||
|
{ |
||||
|
check_null_fl (val, file, line); |
||||
|
} |
||||
|
|
||||
@ -0,0 +1 @@ |
|||||
|
de |
||||
@ -0,0 +1,41 @@ |
|||||
|
# Makefile variables for PO directory in any package using GNU gettext. |
||||
|
|
||||
|
# Usually the message domain is the same as the package name. |
||||
|
DOMAIN = $(PACKAGE) |
||||
|
|
||||
|
# These two variables depend on the location of this directory. |
||||
|
subdir = src/po |
||||
|
top_builddir = ../.. |
||||
|
|
||||
|
# These options get passed to xgettext. |
||||
|
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --keyword=D_ |
||||
|
|
||||
|
# This is the copyright holder that gets inserted into the header of the |
||||
|
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding |
||||
|
# package. (Note that the msgstr strings, extracted from the package's |
||||
|
# sources, belong to the copyright holder of the package.) Translators are |
||||
|
# expected to transfer the copyright for their translations to this person |
||||
|
# or entity, or to disclaim their copyright. The empty string stands for |
||||
|
# the public domain; in this case the translators are expected to disclaim |
||||
|
# their copyright. |
||||
|
COPYRIGHT_HOLDER = Georg Steffers |
||||
|
|
||||
|
# This is the email address or URL to which the translators shall report |
||||
|
# bugs in the untranslated strings: |
||||
|
# - Strings which are not entire sentences, see the maintainer guidelines |
||||
|
# in the GNU gettext documentation, section 'Preparing Strings'. |
||||
|
# - Strings which use unclear terms or require additional context to be |
||||
|
# understood. |
||||
|
# - Strings which make invalid assumptions about notation of date, time or |
||||
|
# money. |
||||
|
# - Pluralisation problems. |
||||
|
# - Incorrect English spelling. |
||||
|
# - Incorrect formatting. |
||||
|
# It can be your email address, or a mailing list address where translators |
||||
|
# can write to without being subscribed, or the URL of a web page through |
||||
|
# which the translators can contact you. |
||||
|
MSGID_BUGS_ADDRESS = georg@steffers.org |
||||
|
|
||||
|
# This is the list of locale categories, beyond LC_MESSAGES, for which the |
||||
|
# message catalogs shall be used. It is usually empty. |
||||
|
EXTRA_LOCALE_CATEGORIES = |
||||
@ -0,0 +1,4 @@ |
|||||
|
src/cmdla.c |
||||
|
src/list.c |
||||
|
src/stack.c |
||||
|
src/exception.c |
||||
@ -0,0 +1,171 @@ |
|||||
|
# German translations for PACKAGE package |
||||
|
# German messages for PACKAGE. |
||||
|
# Copyright (C) 2006 THE PACKAGE'S COPYRIGHT HOLDER |
||||
|
# This file is distributed under the same license as the PACKAGE package. |
||||
|
# Georg Steffers <georg@steffers.org>, 2006. |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: scot 0.0.2\n" |
||||
|
"Report-Msgid-Bugs-To: georg@steffers.org\n" |
||||
|
"POT-Creation-Date: 2006-08-24 07:17+0200\n" |
||||
|
"PO-Revision-Date: 2006-02-22 15:08+0100\n" |
||||
|
"Last-Translator: Georg Steffers <georg@steffers.org>\n" |
||||
|
"Language-Team: German\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#: src/cmdla.c:80 src/cmdla.c:106 src/cmdla.c:373 src/cmdla.c:381 |
||||
|
msgid "help" |
||||
|
msgstr "hilfe" |
||||
|
|
||||
|
#: src/cmdla.c:137 |
||||
|
#, c-format |
||||
|
msgid "Usage: %s [%s] [%s] %s" |
||||
|
msgstr "Verwendung: %s [%s] [%s] %s" |
||||
|
|
||||
|
#: src/cmdla.c:139 src/cmdla.c:143 |
||||
|
msgid "switches" |
||||
|
msgstr "Schalter" |
||||
|
|
||||
|
#: src/cmdla.c:139 src/cmdla.c:162 |
||||
|
msgid "arguments" |
||||
|
msgstr "Argumente" |
||||
|
|
||||
|
#: src/cmdla.c:376 |
||||
|
msgid "gives this help" |
||||
|
msgstr "gibt diese Hilfe" |
||||
|
|
||||
|
#: src/list.c:50 |
||||
|
msgid "[LIST]Failed to create new list." |
||||
|
msgstr "[LIST]Neue Liste anlegen mißlungen." |
||||
|
|
||||
|
#: src/list.c:51 |
||||
|
msgid "[LIST]Failed to free list." |
||||
|
msgstr "[LIST]Liste freigeben mißlungen." |
||||
|
|
||||
|
#: src/list.c:52 |
||||
|
msgid "[LIST]Failed to check for begin of list." |
||||
|
msgstr "[LIST]Test auf Anfang der Liste mißlungen." |
||||
|
|
||||
|
#: src/list.c:53 |
||||
|
msgid "[LIST]Failed to check for end of list." |
||||
|
msgstr "[LIST]Test auf Ende der Liste mißlungen" |
||||
|
|
||||
|
#: src/list.c:54 |
||||
|
msgid "[LIST]Failed to check for list emptiness." |
||||
|
msgstr "[LIST]Test auf leere Liste mißlungen." |
||||
|
|
||||
|
#: src/list.c:55 |
||||
|
msgid "[LIST]Failed to get first list node." |
||||
|
msgstr "[LIST]Ersten Listenknoten holen mißlungen." |
||||
|
|
||||
|
#: src/list.c:56 |
||||
|
msgid "[LIST]Failed to get last list node." |
||||
|
msgstr "[LIST]Letzten Listenknoten holen mißlungen." |
||||
|
|
||||
|
#: src/list.c:57 |
||||
|
msgid "[LIST]Failed to get next list node." |
||||
|
msgstr "[LIST]Nächten Listenknoten holen mißlungen." |
||||
|
|
||||
|
#: src/list.c:58 |
||||
|
msgid "[LIST]Failed to get previous list node." |
||||
|
msgstr "[LIST]Vorigen Listenknoten holen mißlungen." |
||||
|
|
||||
|
#: src/list.c:59 |
||||
|
msgid "[LIST]Failed to find list node." |
||||
|
msgstr "[LIST]Listenknoten finden mißlungen." |
||||
|
|
||||
|
#: src/list.c:60 |
||||
|
msgid "[LIST]Failed to find list anchor." |
||||
|
msgstr "[LIST]Listenanker finden mißlungen." |
||||
|
|
||||
|
#: src/list.c:61 |
||||
|
msgid "[LIST]Failed to retrive the node's value." |
||||
|
msgstr "[LIST]Wert von Knoten holen mißlungen." |
||||
|
|
||||
|
#: src/list.c:62 |
||||
|
msgid "[LIST]Failed to set the node's value." |
||||
|
msgstr "[LIST]Wert von Knoten setzen mißlungen." |
||||
|
|
||||
|
#: src/list.c:63 |
||||
|
msgid "[LIST]Failed to insert node." |
||||
|
msgstr "[LIST]Knoten einfügen mißlungen." |
||||
|
|
||||
|
#: src/list.c:64 |
||||
|
msgid "[LIST]Failed to delete node." |
||||
|
msgstr "[LIST]Knoten löschen mißlungen." |
||||
|
|
||||
|
#: src/list.c:65 |
||||
|
msgid "[LIST]Failed to concatanate the lists." |
||||
|
msgstr "[LIST]Listen aneinander hängen mißlungen." |
||||
|
|
||||
|
#: src/list.c:66 |
||||
|
#, fuzzy |
||||
|
msgid "[LIST]Failed to count list nodes." |
||||
|
msgstr "[LIST]Listenknoten finden mißlungen." |
||||
|
|
||||
|
#: src/list.c:67 |
||||
|
msgid "[LIST]Node is no anchor." |
||||
|
msgstr "[LIST]Knoten ist kein Anker." |
||||
|
|
||||
|
#: src/list.c:68 |
||||
|
msgid "[LIST]Malformed list." |
||||
|
msgstr "Mißbildete Liste." |
||||
|
|
||||
|
#: src/list.c:81 |
||||
|
msgid "[LIST]tried to delete on an empyt list" |
||||
|
msgstr "[LIST]versuch in leerer Liste zu löschen." |
||||
|
|
||||
|
#: src/list.c:111 src/exception.c:747 |
||||
|
msgid "ERROR" |
||||
|
msgstr "FEHLER" |
||||
|
|
||||
|
#: src/list.c:111 src/exception.c:747 |
||||
|
msgid "WARNING" |
||||
|
msgstr "WARNUNG" |
||||
|
|
||||
|
#: src/stack.c:45 |
||||
|
msgid "No more elements left in stack." |
||||
|
msgstr "Keine weiteren Elemente vorhanden." |
||||
|
|
||||
|
#: src/exception.c:244 src/exception.c:327 |
||||
|
msgid "exc_init failed" |
||||
|
msgstr "exc_init fehlgeschlagen" |
||||
|
|
||||
|
#: src/exception.c:311 |
||||
|
msgid "exc_init failed, can't get memory for new list element." |
||||
|
msgstr "" |
||||
|
"exc_init fehlgeschlagen, kann keinen Speicher für neues Listenelement " |
||||
|
"reservieren." |
||||
|
|
||||
|
#: src/exception.c:368 src/exception.c:382 |
||||
|
msgid "excenv_new failed" |
||||
|
msgstr "excenv_new fehlgeschlagen" |
||||
|
|
||||
|
#: src/exception.c:400 |
||||
|
msgid "could not push the new excenv_t into ee_stack:\n" |
||||
|
msgstr "konnte den neuen excenv_t nicht in ee_stack pushen:\n" |
||||
|
|
||||
|
#: src/exception.c:441 |
||||
|
msgid "invalid exception environment\n" |
||||
|
msgstr "ungültige Exception Umgebung\n" |
||||
|
|
||||
|
#: src/exception.c:482 |
||||
|
#, c-format |
||||
|
msgid "" |
||||
|
"any code that THROWs exeptions has to be\n" |
||||
|
"%s within a TRY block\n" |
||||
|
msgstr "" |
||||
|
"jeder code der Exceptions THROWd muß\n" |
||||
|
"%s in einem TRY Block sein\n" |
||||
|
|
||||
|
#: src/exception.c:536 |
||||
|
msgid "use of CATCH with no previous TRY" |
||||
|
msgstr "CATCH ohne vorheriges TRY benutzt" |
||||
|
|
||||
|
#: src/exception.c:606 |
||||
|
msgid "exc_new failed" |
||||
|
msgstr "exc_new fehlgeschlagen" |
||||
@ -0,0 +1,165 @@ |
|||||
|
# SOME DESCRIPTIVE TITLE. |
||||
|
# Copyright (C) YEAR Georg Steffers |
||||
|
# This file is distributed under the same license as the PACKAGE package. |
||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. |
||||
|
# |
||||
|
#, fuzzy |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: PACKAGE VERSION\n" |
||||
|
"Report-Msgid-Bugs-To: georg@steffers.org\n" |
||||
|
"POT-Creation-Date: 2006-08-24 07:17+0200\n" |
||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
||||
|
"Language-Team: LANGUAGE <LL@li.org>\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=CHARSET\n" |
||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||
|
|
||||
|
#: src/cmdla.c:80 src/cmdla.c:106 src/cmdla.c:373 src/cmdla.c:381 |
||||
|
msgid "help" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/cmdla.c:137 |
||||
|
#, c-format |
||||
|
msgid "Usage: %s [%s] [%s] %s" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/cmdla.c:139 src/cmdla.c:143 |
||||
|
msgid "switches" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/cmdla.c:139 src/cmdla.c:162 |
||||
|
msgid "arguments" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/cmdla.c:376 |
||||
|
msgid "gives this help" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:50 |
||||
|
msgid "[LIST]Failed to create new list." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:51 |
||||
|
msgid "[LIST]Failed to free list." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:52 |
||||
|
msgid "[LIST]Failed to check for begin of list." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:53 |
||||
|
msgid "[LIST]Failed to check for end of list." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:54 |
||||
|
msgid "[LIST]Failed to check for list emptiness." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:55 |
||||
|
msgid "[LIST]Failed to get first list node." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:56 |
||||
|
msgid "[LIST]Failed to get last list node." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:57 |
||||
|
msgid "[LIST]Failed to get next list node." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:58 |
||||
|
msgid "[LIST]Failed to get previous list node." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:59 |
||||
|
msgid "[LIST]Failed to find list node." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:60 |
||||
|
msgid "[LIST]Failed to find list anchor." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:61 |
||||
|
msgid "[LIST]Failed to retrive the node's value." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:62 |
||||
|
msgid "[LIST]Failed to set the node's value." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:63 |
||||
|
msgid "[LIST]Failed to insert node." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:64 |
||||
|
msgid "[LIST]Failed to delete node." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:65 |
||||
|
msgid "[LIST]Failed to concatanate the lists." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:66 |
||||
|
msgid "[LIST]Failed to count list nodes." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:67 |
||||
|
msgid "[LIST]Node is no anchor." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:68 |
||||
|
msgid "[LIST]Malformed list." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:81 |
||||
|
msgid "[LIST]tried to delete on an empyt list" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:111 src/exception.c:747 |
||||
|
msgid "ERROR" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/list.c:111 src/exception.c:747 |
||||
|
msgid "WARNING" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/stack.c:45 |
||||
|
msgid "No more elements left in stack." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/exception.c:244 src/exception.c:327 |
||||
|
msgid "exc_init failed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/exception.c:311 |
||||
|
msgid "exc_init failed, can't get memory for new list element." |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/exception.c:368 src/exception.c:382 |
||||
|
msgid "excenv_new failed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/exception.c:400 |
||||
|
msgid "could not push the new excenv_t into ee_stack:\n" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/exception.c:441 |
||||
|
msgid "invalid exception environment\n" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/exception.c:482 |
||||
|
#, c-format |
||||
|
msgid "" |
||||
|
"any code that THROWs exeptions has to be\n" |
||||
|
"%s within a TRY block\n" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/exception.c:536 |
||||
|
msgid "use of CATCH with no previous TRY" |
||||
|
msgstr "" |
||||
|
|
||||
|
#: src/exception.c:606 |
||||
|
msgid "exc_new failed" |
||||
|
msgstr "" |
||||
@ -0,0 +1 @@ |
|||||
|
timestamp |
||||
@ -0,0 +1,136 @@ |
|||||
|
/* |
||||
|
* dir.c: This is the home of the posix-style get_dir_first, get_dir_next. |
||||
|
* Right now, those function only return non-directory filenames. |
||||
|
* (This is because thats what i wanted for checkout_files.) |
||||
|
* |
||||
|
* Copyright (C) 2006 Georg Steffers |
||||
|
* |
||||
|
* Author: Georg Steffers [GST] <georg.steffers@aschendorff.de> |
||||
|
* Developer: |
||||
|
* |
||||
|
* Changes (for this file only): |
||||
|
* (2006-06-12) [GST] Started this changelog...well the program is |
||||
|
* ready since some weeks right now. |
||||
|
*/ |
||||
|
#include <unistd.h> |
||||
|
#include <string.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
#include <scot/dir.h> |
||||
|
#include <scot/exception.h> |
||||
|
|
||||
|
/* |
||||
|
* within the get_dir_... functions one can decide if one wants to follow |
||||
|
* symlinks or not. To achive this i use different stat functions to |
||||
|
* identify files. A variable of this type is capable of holding those |
||||
|
* stat functions. |
||||
|
*/ |
||||
|
typedef int (*stat_func_t) (const char *, struct stat *); |
||||
|
|
||||
|
/* |
||||
|
* This functions tries an opendir on the given path and uses the |
||||
|
* get_dir_next function to retrieve the first file within that directory. |
||||
|
* |
||||
|
* parameters: |
||||
|
* path: The path to the directory that should be read. |
||||
|
* file: A pointer to a structure that holds further information to the |
||||
|
* found file. (e.g. the path to the file) |
||||
|
* fsym: fsym==0 => don't follow symlinks, fsym!=0 => follow symlinks |
||||
|
* |
||||
|
* returns: |
||||
|
* NULL if an error occures or an handle to the opened directory on |
||||
|
* success. This handle should be closed later in the program. |
||||
|
* There should be a function that does this, but as this program |
||||
|
* actually exits anyway after directory reading i have not done it |
||||
|
* right now. |
||||
|
*/ |
||||
|
DIR_HANDLE |
||||
|
get_dir_first (const char * path, FILE_DATA * file, int fsym) |
||||
|
{ |
||||
|
DIR * dir; |
||||
|
|
||||
|
dir = opendir (path); /* !!!FIXME!!! Do error handling here */ |
||||
|
|
||||
|
/* opendir could fail for various reasons, most likely are two. |
||||
|
* The given string does not reflect any file, or is no directory */ |
||||
|
if (NULL == dir) |
||||
|
/* errno is set by opendir */ |
||||
|
return NULL; |
||||
|
|
||||
|
if (get_dir_next (dir, path, file, fsym) != GET_DIRENT_OK) |
||||
|
return NULL; |
||||
|
|
||||
|
return dir; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* This functions retrieves the next file within the given dir. |
||||
|
* |
||||
|
* parameters: |
||||
|
* dir: Handle to a directory opened with get_dir_first previously. |
||||
|
* path: The path to the directory that is read. |
||||
|
* (hmmm, this seems not that ideal to me...why should this |
||||
|
* function construct the full path to the found file. |
||||
|
* The filename is more that enough i think, as the caller knows |
||||
|
* the path already.) |
||||
|
* file: A pointer to a structure that holds further information to the |
||||
|
* found file. (e.g. the path to the file) |
||||
|
* fsym: fsym==0 => don't follow symlinks, fsym!=0 => follow symlinks |
||||
|
* |
||||
|
* returns: |
||||
|
* This function returns always one of the following: |
||||
|
* GET_DIRENT_ERR: if an error occured...errno might or might not be set. |
||||
|
* NO_FILES_LEFT: if the last entry of the directory was read. |
||||
|
* GET_DIRENT_OK: if the next directory entry was read successfully. |
||||
|
*/ |
||||
|
int |
||||
|
get_dir_next (DIR_HANDLE dir, const char * path, FILE_DATA * file, int fsym) |
||||
|
{ |
||||
|
stat_func_t my_stat_f; |
||||
|
|
||||
|
/* first look if we should use a symlink following stat */ |
||||
|
switch (fsym) |
||||
|
{ |
||||
|
case DONT_FOLLOW_SYM: my_stat_f = lstat; break; |
||||
|
case FOLLOW_SYM: |
||||
|
default: my_stat_f = stat;; |
||||
|
} |
||||
|
|
||||
|
strncpy (file->path, path, MAX_PATH); |
||||
|
|
||||
|
/* add a / to path but don't write more than MAX_PATH */ |
||||
|
if (strlen (file->path) < MAX_PATH && |
||||
|
file->path [strlen (file->path)-1] != '/') |
||||
|
{ |
||||
|
file->path [strlen (file->path) + 1] = '\0'; |
||||
|
file->path [strlen (file->path)] = '/'; |
||||
|
} |
||||
|
|
||||
|
/* now fill the given struct dirent_stat */ |
||||
|
errno = 0; |
||||
|
file->file = readdir (dir); |
||||
|
|
||||
|
if (NULL == file->file) |
||||
|
{ |
||||
|
if (NULL != dir) |
||||
|
closedir (dir); |
||||
|
|
||||
|
if (errno != EBADF) |
||||
|
return NO_FILES_LEFT; |
||||
|
|
||||
|
return GET_DIRENT_ERR; |
||||
|
} |
||||
|
|
||||
|
strncpy ( |
||||
|
file->path+strlen (file->path), |
||||
|
file->file->d_name, |
||||
|
MAX_PATH-strlen (file->path)); |
||||
|
|
||||
|
if (my_stat_f (file->path, &(file->stat)) == -1) |
||||
|
{ |
||||
|
/* errno is filled by the stat function */ |
||||
|
return GET_DIRENT_ERR; |
||||
|
} |
||||
|
|
||||
|
return GET_DIRENT_OK; |
||||
|
} |
||||
@ -0,0 +1,133 @@ |
|||||
|
#ifndef WIN32 |
||||
|
# include <sys/time.h> |
||||
|
# include <sys/types.h> |
||||
|
# include <unistd.h> |
||||
|
# include <errno.h> |
||||
|
#else |
||||
|
# include <Windows.h> |
||||
|
#endif |
||||
|
|
||||
|
#include <scot/stream_pool.h> |
||||
|
#include <scot/stream_pool_fraction.h> |
||||
|
|
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/thread.h> |
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/event.h> |
||||
|
|
||||
|
#define GEN_LOCAL |
||||
|
# include <scot/list.h> |
||||
|
#undef GEN_LOCAL |
||||
|
|
||||
|
GEN_LIST_FUNC_PROTO (scot_sp_fraction); |
||||
|
GEN_LIST_IMPL (scot_sp_fraction); |
||||
|
|
||||
|
|
||||
|
static |
||||
|
T_PROC_RET |
||||
|
scot_spf_select_entry_func (void * _sp) |
||||
|
{ |
||||
|
struct scot_sp_fraction * sp = (struct scot_sp_fraction *)_sp; |
||||
|
fd_set run_rfds, run_wfds, run_efds; |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
THREAD_CANCEL_ENABLE; |
||||
|
THREAD_CANCEL_ASYNC; |
||||
|
|
||||
|
sp->thread_id = THREAD_ID; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
FD_ZERO (&run_rfds); |
||||
|
FD_ZERO (&run_wfds); |
||||
|
FD_ZERO (&run_efds); |
||||
|
|
||||
|
while (1) |
||||
|
{ |
||||
|
uint16_t i; |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
if (! THREAD_EQUAL (sp->thread_handle, SELF_THREAD)) |
||||
|
{ |
||||
|
scot_stream_pool_cmd ( |
||||
|
(struct scot_stream_pool *)sp->el, |
||||
|
SCOT_STREAM_POOL_STOP_FRACTION, sp); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
for (i=0; i<SCOT_MAX_FRACTION; i++) |
||||
|
{ |
||||
|
struct scot_stream_pool_event * e = NULL; |
||||
|
SCOT_EVENT_NO eno = 0; |
||||
|
struct scot_stream * st = sp->s_list [i]; |
||||
|
|
||||
|
if (st == NULL) break; |
||||
|
|
||||
|
if (FD_ISSET (st->handle.sock, &run_rfds)) |
||||
|
eno = SCOT_EVENT_STREAM_POOL_READ; |
||||
|
else if (FD_ISSET (st->handle.sock, &run_wfds)) |
||||
|
eno = SCOT_EVENT_STREAM_POOL_WRITE; |
||||
|
else if (FD_ISSET (st->handle.sock, &run_efds)) |
||||
|
eno = SCOT_EVENT_STREAM_POOL_EXCEP; |
||||
|
|
||||
|
if (eno != 0) |
||||
|
{ |
||||
|
while (!scot_stream_is_closed (st)) |
||||
|
{ |
||||
|
/* call callback... */ |
||||
|
e = scot_stream_pool_event_new (e, eno, NULL, 0, st); |
||||
|
scot_event_listener_call_cb (sp->el, (struct scot_event *) e); |
||||
|
scot_event_free ((struct scot_event *) e); |
||||
|
e = NULL; |
||||
|
|
||||
|
if (scot_stream_read_pending (st) != 0) |
||||
|
eno = SCOT_EVENT_STREAM_POOL_READ; |
||||
|
else if (scot_stream_write_pending (st) != 0) |
||||
|
eno = SCOT_EVENT_STREAM_POOL_WRITE; |
||||
|
else |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (scot_stream_is_closed (st)) |
||||
|
{ |
||||
|
scot_spf_remove (sp, st, SCOT_STREAM_POOL_FD_ADD_RMASK| |
||||
|
SCOT_STREAM_POOL_FD_ADD_WMASK| |
||||
|
SCOT_STREAM_POOL_FD_ADD_EMASK); |
||||
|
SCOT_STREAM_FREE (st); |
||||
|
|
||||
|
if (sp->s_count == 0) |
||||
|
{ |
||||
|
scot_stream_pool_cmd ( |
||||
|
(struct scot_stream_pool *)sp->el, |
||||
|
SCOT_STREAM_POOL_STOP_FRACTION, sp); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
run_rfds = sp->rfds; |
||||
|
run_wfds = sp->wfds; |
||||
|
run_efds = sp->efds; |
||||
|
|
||||
|
/* evtl. sollte man hier noch timeout support einbauen, sprich |
||||
|
* das letzte NULL mit einer time austauschen. */ |
||||
|
if (select (sp->max_fd+1, &run_rfds, &run_wfds, &run_efds, NULL) == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
} |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
printf ("Exception in %s (%s, %d)\n", __FUNCTION__, __FILE__, __LINE__); |
||||
|
print_all_exceptions (ee); |
||||
|
|
||||
|
exit (EXIT_FAILURE); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
scot_thread_entry_fptr scot_spf_thread_func[] = |
||||
|
{ |
||||
|
scot_spf_select_entry_func, /* socket */ |
||||
|
scot_spf_select_entry_func, /* pipe */ |
||||
|
scot_spf_select_entry_func /* terminal */ |
||||
|
}; |
||||
@ -0,0 +1,44 @@ |
|||||
|
#include <fcntl.h> |
||||
|
#include <errno.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/exception.h> |
||||
|
|
||||
|
#include <scot_common.h> |
||||
|
|
||||
|
int |
||||
|
scot_stream_get_blocking (struct scot_stream * s) |
||||
|
{ |
||||
|
int flags = fcntl (s->handle.file, F_GETFL); |
||||
|
|
||||
|
if (flags == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
|
||||
|
return ! (flags & O_NONBLOCK); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_stream_set_block (struct scot_stream * s) |
||||
|
{ |
||||
|
int flags = fcntl (s->handle.file, F_GETFL); |
||||
|
|
||||
|
if (flags == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
|
||||
|
if (fcntl (s->handle.file, F_SETFL, flags & ~O_NONBLOCK) == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_stream_set_nonblock (struct scot_stream * s) |
||||
|
{ |
||||
|
int flags = fcntl (s->handle.file, F_GETFL); |
||||
|
|
||||
|
if (flags == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
|
||||
|
if (fcntl ( s->handle.file, F_SETFL, flags | O_NONBLOCK) == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,169 @@ |
|||||
|
#include <setjmp.h> |
||||
|
#include <signal.h> |
||||
|
#include <time.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
#include <scot/thread.h> |
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/scot_int.h> |
||||
|
#include <scot/memory.h> |
||||
|
|
||||
|
struct join_cond_st |
||||
|
{ |
||||
|
pthread_mutex_t join_alarm_mutex; |
||||
|
pthread_cond_t join_alarm_cond; |
||||
|
THREAD_T thread; |
||||
|
}; |
||||
|
|
||||
|
static |
||||
|
T_PROC_RET |
||||
|
join_thread (void * arg) |
||||
|
{ |
||||
|
int status; |
||||
|
struct join_cond_st * join_cond = (struct join_cond_st *) arg; |
||||
|
|
||||
|
THREAD_CANCEL_ENABLE; |
||||
|
THREAD_CANCEL_ASYNC; |
||||
|
|
||||
|
pthread_join (join_cond->thread, NULL); |
||||
|
|
||||
|
status = pthread_cond_signal (&(join_cond->join_alarm_cond)); |
||||
|
if (status != 0) |
||||
|
{ |
||||
|
perror ("problem with sending signal within join"); |
||||
|
} |
||||
|
|
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
thread_new (THREAD_T * handle, T_PROC_RET (*t_proc)(void *), void* arg) |
||||
|
{ |
||||
|
if (pthread_create (handle, NULL, t_proc, arg) != 0) |
||||
|
{ |
||||
|
SCOT_MEM_ZERO (handle, sizeof (THREAD_T)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
thread_end (THREAD_T thread, uint32_t timeout) |
||||
|
{ |
||||
|
int err; |
||||
|
|
||||
|
err = CANCEL_THREAD (thread); |
||||
|
if (err != 0) |
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
err, |
||||
|
"[EVENT_SOURCE_THREAD]cancel request failed")); |
||||
|
|
||||
|
err = JOIN_THREAD (thread, timeout); |
||||
|
if (err == JOIN_TIMEOUT) |
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
err, |
||||
|
"[EVENT_SOURCE_THREAD]timeout exceeded while waiting " |
||||
|
"for threads end")); |
||||
|
if (err == JOIN_ERROR) |
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
err, |
||||
|
"[EVENT_SOURCE_THREAD]failure on waiting for threads end")); |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
thread_join (THREAD_T thread, uint32_t timeout) |
||||
|
{ |
||||
|
int status, |
||||
|
join_state = JOIN_OK; |
||||
|
struct timespec alarm; |
||||
|
pthread_t join_thr; |
||||
|
struct join_cond_st join_cond = |
||||
|
{ |
||||
|
PTHREAD_MUTEX_INITIALIZER, |
||||
|
PTHREAD_COND_INITIALIZER, |
||||
|
thread |
||||
|
}; |
||||
|
|
||||
|
if (timeout == INFINITE) |
||||
|
{ |
||||
|
if (pthread_join (thread, NULL) == 0) |
||||
|
{ |
||||
|
return JOIN_OK; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return JOIN_ERROR; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
alarm.tv_sec = time (NULL) + timeout; |
||||
|
alarm.tv_nsec = 0; |
||||
|
|
||||
|
status = pthread_mutex_lock (&join_cond.join_alarm_mutex); |
||||
|
if (status != 0) |
||||
|
{ |
||||
|
perror ("problem achiving mutex within join"); |
||||
|
} |
||||
|
|
||||
|
NEW_THREAD (&join_thr, join_thread, (void *) &join_cond); |
||||
|
|
||||
|
status = pthread_cond_timedwait ( |
||||
|
&(join_cond.join_alarm_cond), |
||||
|
&(join_cond.join_alarm_mutex), |
||||
|
&alarm); |
||||
|
if (status != 0) |
||||
|
{ |
||||
|
if (status == ETIMEDOUT) |
||||
|
{ |
||||
|
join_state = JOIN_TIMEOUT; |
||||
|
|
||||
|
pthread_cancel (join_thr); |
||||
|
pthread_join (join_thr, NULL); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
perror ("problem with condition wait within join"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return join_state; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
thread_mutex_new (THREAD_MUTEX_T * mutex) |
||||
|
{ |
||||
|
pthread_mutex_init (mutex, NULL); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
thread_cond_new (THREAD_COND_T * cond) |
||||
|
{ |
||||
|
pthread_cond_init (cond, NULL); |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
thread_mutex_lock (THREAD_MUTEX_T * mutex) |
||||
|
{ |
||||
|
if (pthread_mutex_lock (mutex) == 0) |
||||
|
{ |
||||
|
return MUTEX_LOCK_OK; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return MUTEX_LOCK_ERROR; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
thread_cond_wait (THREAD_COND_T * cond, THREAD_COND_CS_T * cs, uint32_t t) |
||||
|
{ |
||||
|
if (t == INFINITE) |
||||
|
return pthread_cond_wait (cond, cs); |
||||
|
else |
||||
|
{ |
||||
|
struct timespec tout; |
||||
|
|
||||
|
tout.tv_sec = time (NULL) + t; |
||||
|
tout.tv_nsec = 0; |
||||
|
|
||||
|
return pthread_cond_timedwait (cond, cs, &tout); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
/** |
||||
|
* \file queue.c |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Internal implementations for queue handling. |
||||
|
* |
||||
|
* This implements the internals for the typesafe queue based on |
||||
|
* typesafe linked lists defines in list.h. |
||||
|
* The only thing one has to remember when one only wants to |
||||
|
* use queues within the own code is to link the code agains |
||||
|
* an object of this and list.c. This is normally done by linking agains |
||||
|
* libscot with an -lscot or similar compiler switch. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#include <stdio.h> |
||||
|
|
||||
|
#include <scot/queue.h> |
||||
|
#include <scot_common.h> |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief Error messages given. |
||||
|
* |
||||
|
* This holds all error messages that go either to the exception system |
||||
|
* or will be printed on stderr if an error occurs within a queue function. |
||||
|
* \attention This is not used actually. |
||||
|
*/ |
||||
|
const char *queue_err_msg[] = |
||||
|
{ |
||||
|
N_("No more elements left in queue."), |
||||
|
NULL |
||||
|
}; |
||||
@ -0,0 +1,33 @@ |
|||||
|
#include <scot/scot_int.h> |
||||
|
|
||||
|
#include <scot_common.h> |
||||
|
|
||||
|
|
||||
|
const char * scot_common_errmsg[] = |
||||
|
{ |
||||
|
"[COMMON]the path-string exceeded the maximum allowed size" |
||||
|
}; |
||||
|
|
||||
|
/* |
||||
|
* returns the maximum exponent of the given value use when creating the |
||||
|
* value with a base2-description. That is for example all |
||||
|
* values between 16 an 31 (including both) will return 4. |
||||
|
* |
||||
|
* This is useful when creating an index from a bitmask value. A bitmask |
||||
|
* with a single bit set would result in an integer index, that is unique |
||||
|
* for every different bit. |
||||
|
* |
||||
|
* Maybe there is some issue with byte ordering here...i am not quite sure |
||||
|
* as i do not use the shifted value and i never interpret single bytes out |
||||
|
* of b2pot. |
||||
|
*/ |
||||
|
int |
||||
|
base2exp (uint32_t b2pot) |
||||
|
{ |
||||
|
int exp = 0; |
||||
|
|
||||
|
for (; b2pot >>= 1; exp ++); |
||||
|
|
||||
|
return exp; |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,60 @@ |
|||||
|
#include <stdio.h> |
||||
|
|
||||
|
#include <scot/scot_exceptions.h> |
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot_common.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
const char *scot_err_msg[] = { |
||||
|
N_("[SCOT]malloc failed"), |
||||
|
N_("[SCOT]NULL pointer not allowed"), |
||||
|
NULL |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
void * |
||||
|
exc_malloc (SIZE_T size) |
||||
|
{ |
||||
|
return exc_malloc_fl (size, __FILE__, __LINE__); |
||||
|
} |
||||
|
|
||||
|
void * |
||||
|
exc_malloc_fl (SIZE_T size, const char *file, int line) |
||||
|
{ |
||||
|
void *a; |
||||
|
|
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
a = SCOT_MEM_GET (size); |
||||
|
|
||||
|
if (a == NULL) |
||||
|
THROW (exc_new ( |
||||
|
EXC_ERROR, |
||||
|
file, |
||||
|
line, |
||||
|
MALLOC_ERR, |
||||
|
D_(scot_err_msg [MALLOC_ERR]))); |
||||
|
|
||||
|
return a; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
check_null (const void *var) |
||||
|
{ |
||||
|
check_null_fl (var, __FILE__, __LINE__); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
check_null_fl (const void *var, const char* file, int line) |
||||
|
{ |
||||
|
bindtextdomain (PACKAGE, LOCALEDIR); |
||||
|
|
||||
|
if (var == NULL) |
||||
|
THROW (exc_new ( |
||||
|
EXC_ERROR, |
||||
|
file, |
||||
|
line, |
||||
|
NULL_PTR_ERR, |
||||
|
D_(scot_err_msg [NULL_PTR_ERR]))); |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,184 @@ |
|||||
|
/* |
||||
|
* some basic berkley socket stuff....far from beeing complete |
||||
|
*/ |
||||
|
#define USE_STRUCT_SCOT_SOCKET |
||||
|
|
||||
|
#include <string.h> |
||||
|
|
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/socket.h> |
||||
|
#include <scot/socket_in.h> |
||||
|
#ifndef WIN32 |
||||
|
# include <scot/socket_un.h> |
||||
|
#endif /* WIN32 */ |
||||
|
|
||||
|
#include <scot_common.h> |
||||
|
|
||||
|
#define SCOT_SOCKET_NEW_FAIL 0 |
||||
|
#define SCOT_SOCKET_LISTEN_FAIL 1 |
||||
|
#define SCOT_SOCKET_ACCEPT_FAIL 2 |
||||
|
#define SCOT_SOCKET_CONNECT_FAIL 3 |
||||
|
#define SCOT_SOCKET_NO_VALID_HOST 4 |
||||
|
#define SCOT_SOCKET_AF_NOT_IMPLEMENTED 5 |
||||
|
const char * scot_socket_errmsg[] = |
||||
|
{ |
||||
|
"[SOCKET]failed to create new socket", |
||||
|
"[SOCKET]failed to listen on port specified with socket", |
||||
|
"[SOCKET]failed to accept connections on socket", |
||||
|
"[SOCKET]failed to connect with socket", |
||||
|
"[SOCKET]invalid hostname", |
||||
|
"[SOCKET]address family not implemented" |
||||
|
}; |
||||
|
|
||||
|
const char * scot_socket_wrnmsg[] = |
||||
|
{ |
||||
|
"[SOCKET]there was already an existent socket file.\n" |
||||
|
" i removed that file to let the new instance of the program\n" |
||||
|
" work, but notice that there might be another instance of this\n" |
||||
|
" program running, that is unusable hence now." |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
|
||||
|
void |
||||
|
scot_socket_init (uint16_t major, uint16_t minor) |
||||
|
{ |
||||
|
#ifdef WIN32 |
||||
|
WORD version = MAKEWORD (major,minor); |
||||
|
WSADATA wsa_data; |
||||
|
|
||||
|
WSAStartup (version, &wsa_data); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_socket_fini (void) |
||||
|
{ |
||||
|
int a; |
||||
|
#ifdef WIN32 |
||||
|
WSACleanup (); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* actualy i found no good reason to bind a socken if one |
||||
|
* dont wants to listen to it too. If i find one i will change this. |
||||
|
*/ |
||||
|
void |
||||
|
scot_socket_listen (const struct scot_socket* s) |
||||
|
{ |
||||
|
excenv_t *ee; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
if (bind (s->socket.handle.sock, s->sa, s->addr_len) == -1) |
||||
|
THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO))); |
||||
|
|
||||
|
if (listen (s->socket.handle.sock, SCOT_SOCKET_BACKLOG) == -1) |
||||
|
THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO))); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
/* |
||||
|
* if we got an Address already in use error on a unix domain |
||||
|
* socket it is most likely because there is a stale socket file |
||||
|
* around. Then we can try to unlink it and retry the listen. |
||||
|
*/ |
||||
|
exception_t * e; |
||||
|
|
||||
|
while (e = retrive_exception (ee)) |
||||
|
{ |
||||
|
#ifndef WIN32 |
||||
|
if (exc_errnum_get (e) == EADDRINUSE && s->sa->sa_family == AF_UNIX) |
||||
|
{ |
||||
|
if (unlink (((struct sockaddr_un *) s->sa)->sun_path) == -1) |
||||
|
{ |
||||
|
THROW (e); |
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_SOCKET_LISTEN_FAIL, |
||||
|
scot_socket_errmsg [SCOT_SOCKET_LISTEN_FAIL])); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
THROW (EXC (EXC_WARNING, |
||||
|
SCOT_SOCKET_UN_FILE_EXISTS, |
||||
|
scot_socket_wrnmsg [SCOT_SOCKET_UN_FILE_EXISTS])); |
||||
|
|
||||
|
free_exception (e); |
||||
|
scot_socket_listen (s); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
#endif |
||||
|
{ |
||||
|
THROW (e); |
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_SOCKET_LISTEN_FAIL, |
||||
|
scot_socket_errmsg [SCOT_SOCKET_LISTEN_FAIL])); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
free_catched (ee); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
struct scot_socket * |
||||
|
scot_socket_accept (const struct scot_socket* s) |
||||
|
{ |
||||
|
switch (s->sa->sa_family) |
||||
|
{ |
||||
|
#ifndef WIN32 |
||||
|
case AF_UNIX: return scot_socket_un_accept (s); |
||||
|
#endif /* WIN32 */ |
||||
|
case AF_INET: return scot_socket_in_accept (s); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_socket_connect (const struct scot_socket * s, const char * adr) |
||||
|
{ |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
switch (s->sa->sa_family) |
||||
|
{ |
||||
|
#ifndef WIN32 |
||||
|
case AF_UNIX: |
||||
|
scot_socket_un_prep_con (s, adr); break; |
||||
|
#endif /* WIN32 */ |
||||
|
case AF_INET: |
||||
|
scot_socket_in_prep_con (s, adr); break; |
||||
|
default: |
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_SOCKET_AF_NOT_IMPLEMENTED, |
||||
|
scot_socket_errmsg [SCOT_SOCKET_AF_NOT_IMPLEMENTED])); |
||||
|
} |
||||
|
|
||||
|
if ((connect (s->socket.handle.sock, s->sa, s->addr_len)) == -1) |
||||
|
THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO))); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
forward_all_exceptions (ee); |
||||
|
|
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_SOCKET_CONNECT_FAIL, |
||||
|
scot_socket_errmsg [SCOT_SOCKET_CONNECT_FAIL])); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_socket_free (struct scot_socket * s) |
||||
|
{ |
||||
|
if (s) |
||||
|
{ |
||||
|
if (s->sa) |
||||
|
SCOT_MEM_FREE (s->sa); |
||||
|
|
||||
|
SCOT_SOCK_CLOSE (s->socket.handle.sock); |
||||
|
SCOT_MEM_FREE (s); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,200 @@ |
|||||
|
/* |
||||
|
* some basic berkley socket stuff....far from beeing complete |
||||
|
*/ |
||||
|
#define USE_STRUCT_SCOT_SOCKET |
||||
|
|
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot_common.h> |
||||
|
#include <scot/socket.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
#ifdef WIN32 |
||||
|
# define hstrerror strerror |
||||
|
#endif |
||||
|
|
||||
|
struct scot_socket * |
||||
|
scot_socket_in_new (const char* proto, const char* service) |
||||
|
{ |
||||
|
struct protoent * ppe; |
||||
|
struct servent * pse; |
||||
|
struct scot_socket * sock = NULL; |
||||
|
int port; |
||||
|
SOCKET handle; |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
if (scot_strisdigit (proto)) |
||||
|
ppe = getprotobynumber (atoi (proto)); |
||||
|
else |
||||
|
ppe = getprotobyname (proto); |
||||
|
|
||||
|
if (ppe == NULL) |
||||
|
THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO))); |
||||
|
|
||||
|
handle = socket (PF_INET, SOCK_STREAM, ppe->p_proto); |
||||
|
|
||||
|
if (handle == INVALID_SOCKET) |
||||
|
THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO))); |
||||
|
|
||||
|
if (scot_strisdigit (service)) |
||||
|
pse = getservbyport (atoi (service), proto); |
||||
|
else |
||||
|
pse = getservbyname (service, proto); |
||||
|
|
||||
|
if (pse == NULL) |
||||
|
port = htons ((unsigned short) atoi (service)); |
||||
|
else |
||||
|
port = pse->s_port; |
||||
|
|
||||
|
sock = SCOT_MEM_GET (sizeof (struct scot_socket)); |
||||
|
SCOT_MEM_ZERO (sock, sizeof (struct scot_socket)); |
||||
|
sock->sa = SCOT_MEM_GET (sizeof (struct sockaddr_in)); |
||||
|
SCOT_MEM_ZERO (sock->sa, sizeof (struct sockaddr_in)); |
||||
|
|
||||
|
sock->socket.handle.sock = handle; |
||||
|
sock->socket.s_type = SCOT_STREAM_TYPE_SOCKET; |
||||
|
|
||||
|
((struct sockaddr_in *) sock->sa)->sin_port = port; |
||||
|
((struct sockaddr_in *) sock->sa)->sin_addr.s_addr = INADDR_ANY; |
||||
|
((struct sockaddr_in *) sock->sa)->sin_family = AF_INET; |
||||
|
|
||||
|
sock->addr_len = sizeof (struct sockaddr_in); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
forward_all_exceptions (ee); |
||||
|
|
||||
|
if (sock != NULL) |
||||
|
{ |
||||
|
if (sock->socket.handle.sock <= 0) |
||||
|
SCOT_SOCK_CLOSE (sock->socket.handle.sock); |
||||
|
|
||||
|
if (sock->sa != NULL) |
||||
|
SCOT_MEM_FREE (sock->sa); |
||||
|
|
||||
|
SCOT_MEM_FREE (sock); |
||||
|
} |
||||
|
|
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_SOCKET_NEW_FAIL, |
||||
|
scot_socket_errmsg [SCOT_SOCKET_NEW_FAIL])); |
||||
|
} |
||||
|
|
||||
|
return sock; |
||||
|
} |
||||
|
|
||||
|
struct scot_socket * |
||||
|
scot_socket_in_accept (const struct scot_socket* s) |
||||
|
{ |
||||
|
SOCKET handle; |
||||
|
#ifndef WIN32 |
||||
|
SIZE_T addr_len; |
||||
|
#else |
||||
|
int addr_len; |
||||
|
#endif |
||||
|
struct sockaddr sa; |
||||
|
|
||||
|
struct scot_socket * sock = NULL; |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
addr_len = s->addr_len; |
||||
|
|
||||
|
handle = accept (s->socket.handle.sock, &sa, &addr_len); |
||||
|
if (handle == INVALID_SOCKET) |
||||
|
THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO))); |
||||
|
|
||||
|
/* |
||||
|
* ich reserviere erst hier den speicher für den neuen socket falls |
||||
|
* ein signal accept unterbricht und das programm evtl. abbricht. |
||||
|
* so bleibt garantiert kein reservierter speicher in diesem Fall |
||||
|
* zurück. Solange das ganze Programm abbricht währe das kein Problem, |
||||
|
* falls der aufruf aber in einem thread erfolgt so würde diese thread |
||||
|
* abbrechen und das memory leaken....(wenn es vor dem accept reserviert |
||||
|
* worden währe.) |
||||
|
*/ |
||||
|
sock = SCOT_MEM_GET (sizeof (struct scot_socket)); |
||||
|
SCOT_MEM_ZERO (sock, sizeof (struct scot_socket)); |
||||
|
sock->sa = SCOT_MEM_GET (sizeof (struct sockaddr_in)); |
||||
|
SCOT_MEM_ZERO (sock->sa, sizeof (struct sockaddr_in)); |
||||
|
|
||||
|
sock->addr_len = addr_len; |
||||
|
sock->socket.handle.sock = handle; |
||||
|
sock->socket.s_type = SCOT_STREAM_TYPE_SOCKET; |
||||
|
SCOT_MEM_COPY (sock->sa, &sa, sizeof (struct sockaddr_in)); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
forward_all_exceptions (ee); |
||||
|
|
||||
|
if (sock != NULL) |
||||
|
{ |
||||
|
if (sock->socket.handle.sock <= 0) |
||||
|
SCOT_SOCK_CLOSE (sock->socket.handle.sock); |
||||
|
|
||||
|
if (sock->sa != NULL) |
||||
|
SCOT_MEM_FREE (sock->sa); |
||||
|
|
||||
|
SCOT_MEM_FREE (sock); |
||||
|
} |
||||
|
|
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_SOCKET_ACCEPT_FAIL, |
||||
|
scot_socket_errmsg [SCOT_SOCKET_ACCEPT_FAIL])); |
||||
|
} |
||||
|
|
||||
|
return sock; |
||||
|
} |
||||
|
|
||||
|
const |
||||
|
char * |
||||
|
scot_socket_in_get_host (struct scot_socket * s) |
||||
|
{ |
||||
|
struct hostent * phe; |
||||
|
|
||||
|
phe = gethostbyaddr ( |
||||
|
(char *) &(((struct sockaddr_in *) s->sa)->sin_addr.s_addr), |
||||
|
sizeof (unsigned long), |
||||
|
AF_INET); |
||||
|
|
||||
|
if (!phe) |
||||
|
THROW (EXC (EXC_WARNING, SCOT_H_ERRNO, hstrerror (SCOT_H_ERRNO))); |
||||
|
|
||||
|
return phe->h_name; |
||||
|
} |
||||
|
|
||||
|
const |
||||
|
char * |
||||
|
scot_socket_in_get_ddc (struct scot_socket * s) |
||||
|
{ |
||||
|
return inet_ntoa (((struct sockaddr_in *) s->sa)->sin_addr); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_socket_in_prep_con (const struct scot_socket * s, const char * adr) |
||||
|
{ |
||||
|
struct hostent * phe; |
||||
|
|
||||
|
phe = gethostbyname (adr); |
||||
|
|
||||
|
if (phe) |
||||
|
{ |
||||
|
SCOT_MEM_COPY ( |
||||
|
(char*) &(((struct sockaddr_in *) s->sa)->sin_addr), |
||||
|
phe->h_addr, |
||||
|
phe->h_length); |
||||
|
} |
||||
|
#ifndef WIN32 |
||||
|
else |
||||
|
{ |
||||
|
if (inet_aton (adr, &(((struct sockaddr_in *) s->sa)->sin_addr)) == 0) |
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_SOCKET_NO_VALID_HOST, |
||||
|
scot_socket_errmsg [SCOT_SOCKET_NO_VALID_HOST])); |
||||
|
} |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,149 @@ |
|||||
|
/* |
||||
|
* some basic berkley socket stuff....far from beeing complete |
||||
|
*/ |
||||
|
#include <sys/socket.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/un.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
#define USE_STRUCT_SCOT_SOCKET |
||||
|
|
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot/socket.h> |
||||
|
#include <scot_common.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
struct scot_socket * |
||||
|
scot_socket_un_new (const char* path) |
||||
|
{ |
||||
|
struct scot_socket * sock = NULL; |
||||
|
excenv_t * ee; |
||||
|
SOCKET handle; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
handle = socket (PF_UNIX, SOCK_STREAM, 0); |
||||
|
|
||||
|
if (handle == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
|
||||
|
if (SCOT_STR_LENGTH (path) > UNIX_PATH_MAX) |
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_UNX_PATH_TO_LONG, |
||||
|
scot_common_errmsg [SCOT_UNX_PATH_TO_LONG])); |
||||
|
|
||||
|
sock = SCOT_MEM_GET (sizeof (struct scot_socket)); |
||||
|
SCOT_MEM_ZERO (sock, sizeof (struct scot_socket)); |
||||
|
sock->sa = SCOT_MEM_GET (sizeof (struct sockaddr_un)); |
||||
|
SCOT_MEM_ZERO (sock->sa, sizeof (struct sockaddr_un)); |
||||
|
|
||||
|
((struct sockaddr_un *) sock->sa)->sun_family = AF_UNIX; |
||||
|
SCOT_STRN_COPY ( |
||||
|
((struct sockaddr_un *) sock->sa)->sun_path, |
||||
|
path, |
||||
|
UNIX_PATH_MAX); |
||||
|
|
||||
|
sock->socket.handle.sock = handle; |
||||
|
sock->socket.s_type = SCOT_STREAM_TYPE_SOCKET; |
||||
|
sock->addr_len = |
||||
|
sizeof (((struct sockaddr_un *) sock->sa)->sun_family) + |
||||
|
SCOT_STR_LENGTH (((struct sockaddr_un *) sock->sa)->sun_path); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
forward_all_exceptions (ee); |
||||
|
|
||||
|
if (sock != NULL) |
||||
|
{ |
||||
|
if (sock->socket.handle.sock <= 0) |
||||
|
SCOT_SOCK_CLOSE (sock->socket.handle.sock); |
||||
|
|
||||
|
if (sock->sa != NULL) |
||||
|
SCOT_MEM_FREE (sock->sa); |
||||
|
|
||||
|
SCOT_MEM_FREE (sock); |
||||
|
} |
||||
|
|
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_SOCKET_NEW_FAIL, |
||||
|
scot_socket_errmsg [SCOT_SOCKET_NEW_FAIL])); |
||||
|
} |
||||
|
|
||||
|
return sock; |
||||
|
} |
||||
|
|
||||
|
const |
||||
|
char * |
||||
|
scot_socket_un_get_path (const struct scot_socket* s) |
||||
|
{ |
||||
|
return ((struct sockaddr_un *) s->sa)->sun_path; |
||||
|
} |
||||
|
|
||||
|
struct scot_socket * |
||||
|
scot_socket_un_accept (const struct scot_socket* s) |
||||
|
{ |
||||
|
struct scot_socket * sock = NULL; |
||||
|
excenv_t * ee; |
||||
|
SOCKET handle; |
||||
|
struct sockaddr sa; |
||||
|
SIZE_T addr_len; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
addr_len = s->addr_len; |
||||
|
|
||||
|
handle = accept (s->socket.handle.sock, &sa, &addr_len); |
||||
|
if (handle == -1) |
||||
|
THROW (EXC (EXC_ERROR, errno, strerror (errno))); |
||||
|
|
||||
|
sock = SCOT_MEM_GET (sizeof (struct scot_socket)); |
||||
|
SCOT_MEM_ZERO (sock, sizeof (struct scot_socket)); |
||||
|
sock->sa = SCOT_MEM_GET (sizeof (struct sockaddr_un)); |
||||
|
SCOT_MEM_ZERO (sock->sa, sizeof (struct sockaddr_un)); |
||||
|
|
||||
|
sock->addr_len = addr_len; |
||||
|
sock->socket.handle.sock = handle; |
||||
|
sock->socket.s_type = SCOT_STREAM_TYPE_SOCKET; |
||||
|
SCOT_MEM_COPY (sock->sa, &sa, sizeof (struct sockaddr_un)); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
forward_all_exceptions (ee); |
||||
|
|
||||
|
if (sock != NULL) |
||||
|
{ |
||||
|
if (sock->socket.handle.sock <= 0) |
||||
|
SCOT_SOCK_CLOSE (sock->socket.handle.sock); |
||||
|
|
||||
|
if (sock->sa != NULL) |
||||
|
SCOT_MEM_FREE (sock->sa); |
||||
|
|
||||
|
SCOT_MEM_FREE (sock); |
||||
|
} |
||||
|
|
||||
|
THROW (EXC (EXC_ERROR, |
||||
|
SCOT_SOCKET_ACCEPT_FAIL, |
||||
|
scot_socket_errmsg [SCOT_SOCKET_ACCEPT_FAIL])); |
||||
|
} |
||||
|
|
||||
|
return sock; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_socket_un_prep_con (struct scot_socket * s, const char * adr) |
||||
|
{ |
||||
|
if (adr) |
||||
|
{ |
||||
|
SCOT_STRN_COPY ( |
||||
|
((struct sockaddr_un *) s->sa)->sun_path, |
||||
|
adr, |
||||
|
UNIX_PATH_MAX); |
||||
|
|
||||
|
s->addr_len = |
||||
|
sizeof (((struct sockaddr_un *) s->sa)->sun_family) + |
||||
|
SCOT_STR_LENGTH (((struct sockaddr_un *) s->sa)->sun_path); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,47 @@ |
|||||
|
/** |
||||
|
* \file stack.c |
||||
|
* \author Georg Steffers <georg@steffers.org> |
||||
|
* \brief Internal implementations for stack handling. |
||||
|
* |
||||
|
* This implements the internals for the typesafe stack based on |
||||
|
* typesafe linked lists defines in list.h. |
||||
|
* The only thing one has to remember when one only wants to |
||||
|
* use stacks within the own code is to link the code agains |
||||
|
* an object of this and list.c. This is normally done by linking agains |
||||
|
* libscot with an -lscot or similar compiler switch. |
||||
|
* |
||||
|
* Copyright (C)2006 Georg Steffers <georg@steffers.org> |
||||
|
* |
||||
|
* This program is free software; you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation; either version 2 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program; if not, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
*/ |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
#include <scot/stack.h> |
||||
|
#include <scot_common.h> |
||||
|
|
||||
|
/** |
||||
|
* \internal |
||||
|
* \brief Error messages given. |
||||
|
* |
||||
|
* This holds all error messages that go either to the exception system |
||||
|
* or will be printed on stderr if an error occurs within a stack function. |
||||
|
* \attention This is not used actually. |
||||
|
*/ |
||||
|
const char *stack_err_msg[] = |
||||
|
{ |
||||
|
N_("No more elements left in stack."), |
||||
|
NULL |
||||
|
}; |
||||
@ -0,0 +1,189 @@ |
|||||
|
#include <sys/types.h> |
||||
|
#include <unistd.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
#ifndef WIN32 |
||||
|
# include <sys/ioctl.h> |
||||
|
#else |
||||
|
# include <Windows.h> |
||||
|
# include <Winsock2.h> |
||||
|
#endif |
||||
|
|
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/socket.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
#include <scot_common.h> |
||||
|
|
||||
|
static |
||||
|
SSIZE_T |
||||
|
scot_read (struct scot_stream * st, SIZE_T count) |
||||
|
{ |
||||
|
switch (st->s_type) |
||||
|
{ |
||||
|
case (SCOT_STREAM_TYPE_SOCKET): |
||||
|
return recv (st->handle.sock, st->rbuf, count, 0); |
||||
|
case (SCOT_STREAM_TYPE_FILE): |
||||
|
case (SCOT_STREAM_TYPE_PIPE): |
||||
|
case (SCOT_STREAM_TYPE_INOTIFY): |
||||
|
return SCOT_FILE_READ (st->handle.file, st->rbuf, count); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
scot_stream_eof (struct scot_stream * st) |
||||
|
{ |
||||
|
/* if there is still data in the buffer we have no eof */ |
||||
|
if (st->rbuf_idx != 0) |
||||
|
return 0; |
||||
|
|
||||
|
/* try to read data in the buffer */ |
||||
|
st->rbuf_idx = scot_read (st, SCOT_STREAM_BUF_SIZE); |
||||
|
|
||||
|
if (st->rbuf_idx == 0) |
||||
|
return 1; |
||||
|
|
||||
|
/* if no data was available reset the idx to 0 */ |
||||
|
if (st->rbuf_idx == -1) |
||||
|
switch (SCOT_ERRNO) |
||||
|
{ |
||||
|
#ifndef WIN32 |
||||
|
case (EAGAIN): st->rbuf_idx = 0; return 0; |
||||
|
#else |
||||
|
case (WSAECONNRESET): st->rbuf_idx = 0; return 1; |
||||
|
case (WSAEWOULDBLOCK): st->rbuf_idx = 0; return 0; |
||||
|
#endif |
||||
|
default: THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO))); |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
SSIZE_T |
||||
|
scot_stream_read_copy_buffers (struct scot_stream * s, char * dest, SIZE_T c) |
||||
|
{ |
||||
|
SSIZE_T ret = 0; |
||||
|
|
||||
|
if (c <= s->rbuf_idx) |
||||
|
{ |
||||
|
SCOT_MEM_COPY (dest, s->rbuf, c); |
||||
|
SCOT_MEM_MOVE (s->rbuf, s->rbuf + c, s->rbuf_idx - c); |
||||
|
s->rbuf_idx -= c; |
||||
|
ret = c; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
SCOT_MEM_COPY (dest, s->rbuf, s->rbuf_idx); |
||||
|
ret = s->rbuf_idx; |
||||
|
s->rbuf_idx = 0; |
||||
|
} |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
SSIZE_T |
||||
|
scot_stream_read_buffered (struct scot_stream * st, char * buffer, SIZE_T count) |
||||
|
{ |
||||
|
SSIZE_T ret; |
||||
|
SIZE_T size = SCOT_STREAM_BUF_SIZE; |
||||
|
|
||||
|
if ((ret = scot_stream_read_copy_buffers (st, buffer, count)) == count) |
||||
|
return count; |
||||
|
|
||||
|
#ifndef WIN32 |
||||
|
if (st->s_type == SCOT_STREAM_TYPE_INOTIFY) |
||||
|
{ |
||||
|
ioctl (st->handle.file, FIONREAD, &size); |
||||
|
size = (size <= SCOT_STREAM_BUF_SIZE)?size:SCOT_STREAM_BUF_SIZE; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
while (ret != count) |
||||
|
{ |
||||
|
SIZE_T read_c; |
||||
|
|
||||
|
read_c = st->rbuf_idx = scot_read (st, size); |
||||
|
|
||||
|
if (st->rbuf_idx == -1) |
||||
|
switch (SCOT_ERRNO) |
||||
|
{ |
||||
|
#ifndef WIN32 |
||||
|
case (EAGAIN): st->rbuf_idx = 0; return 0; |
||||
|
#else |
||||
|
case (WSAECONNRESET): st->rbuf_idx = 0; return ret; |
||||
|
case (WSAEWOULDBLOCK): st->rbuf_idx = 0; return 0; |
||||
|
#endif |
||||
|
default: THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO))); |
||||
|
} |
||||
|
|
||||
|
ret += scot_stream_read_copy_buffers (st, buffer+ret, count-ret); |
||||
|
|
||||
|
if (read_c != size) |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
SSIZE_T |
||||
|
scot_stream_read (struct scot_stream * st, char * buffer, SIZE_T count) |
||||
|
{ |
||||
|
return scot_stream_read_buffered (st, buffer, count); |
||||
|
} |
||||
|
|
||||
|
SSIZE_T |
||||
|
scot_stream_write (struct scot_stream * st, char * buffer, SIZE_T count) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
SSIZE_T scot_stream_read_pending (struct scot_stream * st) |
||||
|
{ |
||||
|
return st->rbuf_idx; |
||||
|
} |
||||
|
|
||||
|
SSIZE_T scot_stream_write_pending (struct scot_stream * st) |
||||
|
{ |
||||
|
return st->wbuf_idx; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_stream_flush (struct scot_stream * st) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
scot_stream_is_closed (struct scot_stream * st) |
||||
|
{ |
||||
|
return (st!=NULL && st->rbuf_idx==-1)?1:0; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_stream_close (struct scot_stream * st) |
||||
|
{ |
||||
|
switch (st->s_type) |
||||
|
{ |
||||
|
case (SCOT_STREAM_TYPE_SOCKET): |
||||
|
SCOT_SOCK_CLOSE (st->handle.sock); |
||||
|
break; |
||||
|
default: |
||||
|
#ifndef WIN32 |
||||
|
close (st->handle.file); |
||||
|
#endif |
||||
|
break; |
||||
|
} |
||||
|
SCOT_MEM_ZERO (st->rbuf, SCOT_STREAM_BUF_SIZE); |
||||
|
SCOT_MEM_ZERO (st->wbuf, SCOT_STREAM_BUF_SIZE); |
||||
|
st->rbuf_idx = -1; |
||||
|
st->wbuf_idx = -1; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_stream_free (struct scot_stream * st) |
||||
|
{ |
||||
|
SCOT_STREAM_FREE (st); |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,328 @@ |
|||||
|
#include <sys/types.h> |
||||
|
#include <unistd.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
#include <scot/stream_pool.h> |
||||
|
#include <scot/stream_pool_fraction.h> |
||||
|
|
||||
|
#include <scot/event_listener.h> |
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/event.h> |
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot/thread.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
#define GEN_LOCAL |
||||
|
# include <scot/list.h> |
||||
|
#undef GEN_LOCAL |
||||
|
|
||||
|
GEN_LIST_FUNC_PROTO (scot_sp_fraction); |
||||
|
GEN_LIST_IMPL (scot_sp_fraction); |
||||
|
|
||||
|
/* |
||||
|
* static functions for this file |
||||
|
* ---------------------------------------------------------------------- |
||||
|
*/ |
||||
|
static |
||||
|
unsigned short |
||||
|
scot_stream_pool_default_cb (struct scot_event * _e) |
||||
|
{ |
||||
|
SSIZE_T n; |
||||
|
char puffer[1024]; |
||||
|
struct scot_stream_pool_event * e = (struct scot_stream_pool_event *) _e; |
||||
|
|
||||
|
if (_e->event == SCOT_EVENT_STREAM_POOL_READ) |
||||
|
{ |
||||
|
if (scot_stream_eof (e->st)) |
||||
|
{ |
||||
|
printf ("Connection closed by foreign host\n"); |
||||
|
scot_stream_close (e->st); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
n = scot_stream_read (e->st, puffer, 1024); |
||||
|
printf ("read possible on %d (%d bytes read)\n", e->st->handle, n); |
||||
|
} |
||||
|
} |
||||
|
if (_e->event == SCOT_EVENT_STREAM_POOL_WRITE) |
||||
|
printf ("write possible on %d (%d bytes read)\n", e->st->handle, n); |
||||
|
if (_e->event == SCOT_EVENT_STREAM_POOL_EXCEP) |
||||
|
printf ("exception on %d (%d bytes read)\n", e->st->handle, n); |
||||
|
|
||||
|
fflush (stdout); |
||||
|
|
||||
|
return SCOT_EVENT_END; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
main_thread_fini (void * arg) |
||||
|
{ |
||||
|
struct scot_stream_pool * pool = (struct scot_stream_pool *) arg; |
||||
|
list_scot_sp_fraction_node_t * f_node = pool->pool; |
||||
|
struct scot_sp_fraction * f; |
||||
|
|
||||
|
LOCK_THREAD_MUTEX (&pool->mutex); |
||||
|
/* this assures that the thread_fini does not try |
||||
|
* to wake the main thread for cleanup.... |
||||
|
* (done because main thread is finalized here) */ |
||||
|
((struct scot_event_listener *) arg)->thread_run_flg = 0; |
||||
|
|
||||
|
while (! list_scot_sp_fraction_eol (pool->pool, f_node)) |
||||
|
{ |
||||
|
f_node = list_scot_sp_fraction_next (f_node); |
||||
|
f = list_scot_sp_fraction_retrive (f_node); |
||||
|
|
||||
|
if (f->thread_run_flg != 0) |
||||
|
{ |
||||
|
DETACH_THREAD (f->thread_handle); |
||||
|
CANCEL_THREAD (f->thread_handle); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
UNLOCK_THREAD_MUTEX (&pool->mutex); |
||||
|
|
||||
|
exc_end (); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* entry point für einen stream-pool event-source thread. |
||||
|
*/ |
||||
|
static |
||||
|
void |
||||
|
scot_stream_pool_main_loop (struct scot_stream_pool * sp) |
||||
|
{ |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
LOCK_THREAD_MUTEX (&sp->mutex); |
||||
|
|
||||
|
((struct scot_event_listener *) sp)->thread_id = THREAD_ID; |
||||
|
((struct scot_event_listener *) sp)->thread_run_flg = 1; |
||||
|
|
||||
|
THREAD_CANCEL_ENABLE; |
||||
|
THREAD_CANCEL_DEFER; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
list_scot_sp_fraction_node_t * f_node = sp->pool; |
||||
|
struct scot_sp_fraction * f; |
||||
|
|
||||
|
THREAD_ATEXIT_BEGIN (main_thread_fini, sp); |
||||
|
|
||||
|
/* |
||||
|
* starte all threads und suspende in einen cancellation point... |
||||
|
* Das könnte ich nochmal überdenken, immerhin kann ich mit |
||||
|
* diesem thread evtl. noch mehr anfangen. Z.B. Funktionen die |
||||
|
* in wecken, damit er alle threads stoppt (bzw. startet). |
||||
|
* Einzelne threads neu starten etc. Die Logik dafür könnte |
||||
|
* glaube ich gut in dieser Funktion liegen..... |
||||
|
* Vielleicht aber auch nicht. |
||||
|
*/ |
||||
|
while (! list_scot_sp_fraction_eol (sp->pool, f_node)) |
||||
|
{ |
||||
|
f_node = list_scot_sp_fraction_next (f_node); |
||||
|
f = list_scot_sp_fraction_retrive (f_node); |
||||
|
|
||||
|
NEW_THREAD (&f->thread_handle, f->spf_entry_func, f); |
||||
|
f->thread_run_flg = 1; |
||||
|
} |
||||
|
|
||||
|
UNLOCK_THREAD_MUTEX (&sp->mutex); |
||||
|
|
||||
|
while (1) |
||||
|
{ |
||||
|
THREAD_COND_ENTER_CS (&sp->cmd_cs); |
||||
|
|
||||
|
WAIT_THREAD_COND (&sp->cmd_cond, &sp->cmd_cs, INFINITE); |
||||
|
|
||||
|
switch (sp->cmd) |
||||
|
{ |
||||
|
case SCOT_STREAM_POOL_RESTART_ALL_FRAC: |
||||
|
f_node = sp->pool; |
||||
|
while (! list_scot_sp_fraction_eol (sp->pool, f_node)) |
||||
|
{ |
||||
|
f_node = list_scot_sp_fraction_next (f_node); |
||||
|
f = list_scot_sp_fraction_retrive (f_node); |
||||
|
|
||||
|
if (f->thread_run_flg != 0) |
||||
|
{ |
||||
|
END_THREAD (f->thread_handle, INFINITE); |
||||
|
thread_exc_end (f->thread_handle); |
||||
|
} |
||||
|
NEW_THREAD (&f->thread_handle, f->spf_entry_func, f); |
||||
|
f->thread_run_flg = 1; |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case SCOT_STREAM_POOL_START_ALL_FRAC: |
||||
|
f_node = sp->pool; |
||||
|
while (! list_scot_sp_fraction_eol (sp->pool, f_node)) |
||||
|
{ |
||||
|
f_node = list_scot_sp_fraction_next (f_node); |
||||
|
f = list_scot_sp_fraction_retrive (f_node); |
||||
|
|
||||
|
if (f->thread_run_flg == 0) |
||||
|
{ |
||||
|
NEW_THREAD (&f->thread_handle, f->spf_entry_func, f); |
||||
|
f->thread_run_flg = 1; |
||||
|
} |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case SCOT_STREAM_POOL_STOP_ALL_FRAC: |
||||
|
f_node = sp->pool; |
||||
|
while (! list_scot_sp_fraction_eol (sp->pool, f_node)) |
||||
|
{ |
||||
|
f_node = list_scot_sp_fraction_next (f_node); |
||||
|
f = list_scot_sp_fraction_retrive (f_node); |
||||
|
|
||||
|
if (f->thread_run_flg != 0) |
||||
|
{ |
||||
|
END_THREAD (f->thread_handle, INFINITE); |
||||
|
thread_exc_end (f->thread_handle); |
||||
|
f->thread_run_flg = 0; |
||||
|
} |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case SCOT_STREAM_POOL_RESTART_FRACTION: |
||||
|
f = (struct scot_sp_fraction *) sp->cmd_arg; |
||||
|
if (f->thread_run_flg != 0) |
||||
|
{ |
||||
|
END_THREAD (f->thread_handle, INFINITE); |
||||
|
thread_exc_end (f->thread_handle); |
||||
|
} |
||||
|
NEW_THREAD (&f->thread_handle, f->spf_entry_func, f); |
||||
|
f->thread_run_flg = 1; |
||||
|
break; |
||||
|
|
||||
|
case SCOT_STREAM_POOL_START_FRACTION: |
||||
|
f = (struct scot_sp_fraction *) sp->cmd_arg; |
||||
|
if (f->thread_run_flg == 0) |
||||
|
{ |
||||
|
NEW_THREAD (&f->thread_handle, f->spf_entry_func, f); |
||||
|
f->thread_run_flg = 1; |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case SCOT_STREAM_POOL_STOP_FRACTION: |
||||
|
f = (struct scot_sp_fraction *) sp->cmd_arg; |
||||
|
if (f->thread_run_flg != 0) |
||||
|
{ |
||||
|
END_THREAD (f->thread_handle, INFINITE); |
||||
|
thread_exc_end (f->thread_handle); |
||||
|
f->thread_run_flg = 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* now we do a cleanup. That is |
||||
|
* we remove empty fractions from the stream pool. |
||||
|
*/ |
||||
|
f_node = sp->pool; |
||||
|
while (!list_scot_sp_fraction_eol (sp->pool, f_node)) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
f_node = list_scot_sp_fraction_next (f_node); |
||||
|
f = list_scot_sp_fraction_retrive (f_node); |
||||
|
|
||||
|
if (f->s_count == 0) |
||||
|
{ |
||||
|
if (f->thread_run_flg != 0) |
||||
|
{ |
||||
|
END_THREAD (f->thread_handle, INFINITE); |
||||
|
thread_exc_end (f->thread_handle); |
||||
|
f->thread_run_flg = 0; |
||||
|
} |
||||
|
|
||||
|
list_scot_sp_fraction_delete (f_node); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
THREAD_COND_LEAVE_CS (&sp->cmd_cs); |
||||
|
} |
||||
|
|
||||
|
THREAD_ATEXIT_END (0); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
print_all_exceptions (ee); |
||||
|
|
||||
|
exit (EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
main_thread_fini (sp); |
||||
|
} |
||||
|
|
||||
|
/* ---------------------------------------------------------------------- */ |
||||
|
|
||||
|
|
||||
|
struct scot_stream_pool * |
||||
|
scot_stream_pool_new (struct scot_stream_pool * sp) |
||||
|
{ |
||||
|
sp = SCOT_MEM_GET (sizeof (struct scot_stream_pool)); |
||||
|
SCOT_MEM_ZERO (sp, sizeof (struct scot_stream_pool)); |
||||
|
|
||||
|
sp->pool = list_scot_sp_fraction_new (sp->pool); |
||||
|
|
||||
|
if (! list_scot_sp_fraction_elem_free_is_set ()) |
||||
|
list_scot_sp_fraction_set_elem_free (scot_spf_free); |
||||
|
|
||||
|
scot_event_listener_init ( |
||||
|
(struct scot_event_listener *) sp, |
||||
|
SCOT_EG_STREAM_POOL, |
||||
|
(scot_thread_entry_fptr) scot_stream_pool_main_loop); |
||||
|
|
||||
|
scot_event_listener_register_cb ( |
||||
|
(struct scot_event_listener *) sp, |
||||
|
SCOT_EVENT_STREAM_POOL_READ, |
||||
|
scot_stream_pool_default_cb, NULL); |
||||
|
scot_event_listener_register_cb ( |
||||
|
(struct scot_event_listener *) sp, |
||||
|
SCOT_EVENT_STREAM_POOL_WRITE, |
||||
|
scot_stream_pool_default_cb, NULL); |
||||
|
scot_event_listener_register_cb ( |
||||
|
(struct scot_event_listener *) sp, |
||||
|
SCOT_EVENT_STREAM_POOL_EXCEP, |
||||
|
scot_stream_pool_default_cb, NULL); |
||||
|
|
||||
|
NEW_THREAD_MUTEX (&sp->mutex); |
||||
|
NEW_THREAD_COND (&sp->cmd_cond); |
||||
|
NEW_THREAD_COND_CS (&sp->cmd_cs); |
||||
|
|
||||
|
return sp; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_stream_pool_free (struct scot_stream_pool * sp) |
||||
|
{ |
||||
|
scot_stream_pool_cmd (sp, SCOT_STREAM_POOL_STOP_ALL_FRAC, NULL); |
||||
|
|
||||
|
scot_event_listener_fini ((struct scot_event_listener *) sp); |
||||
|
|
||||
|
list_scot_sp_fraction_free (sp->pool); |
||||
|
|
||||
|
FREE_THREAD_MUTEX (&sp->mutex); |
||||
|
FREE_THREAD_COND (&sp->cmd_cond); |
||||
|
FREE_THREAD_COND_CS (&sp->cmd_cs); |
||||
|
|
||||
|
SCOT_MEM_FREE (sp); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_stream_pool_free_s (struct scot_stream_pool * sp, int free_s) |
||||
|
{ |
||||
|
list_scot_sp_fraction_node_t * spf_node = sp->pool; |
||||
|
|
||||
|
while (! list_scot_sp_fraction_eol (sp->pool, spf_node)) |
||||
|
{ |
||||
|
struct scot_sp_fraction * f; |
||||
|
|
||||
|
spf_node = list_scot_sp_fraction_next (spf_node); |
||||
|
f = list_scot_sp_fraction_retrive (spf_node); |
||||
|
|
||||
|
scot_spf_free_s (f, free_s); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,154 @@ |
|||||
|
#ifndef WIN32 |
||||
|
# include <sys/select.h> |
||||
|
# include <sys/types.h> |
||||
|
# include <unistd.h> |
||||
|
# include <errno.h> |
||||
|
#else |
||||
|
# include <Windows.h> |
||||
|
# include <Winsock2.h> |
||||
|
#endif |
||||
|
|
||||
|
#include <scot/stream_pool.h> |
||||
|
#include <scot/stream_pool_fraction.h> |
||||
|
|
||||
|
#include <scot/event_listener.h> |
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/event.h> |
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot/thread.h> |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* static functions for this file |
||||
|
* ---------------------------------------------------------------------- |
||||
|
*/ |
||||
|
/* ---------------------------------------------------------------------- */ |
||||
|
|
||||
|
struct scot_sp_fraction * |
||||
|
scot_spf_new (struct scot_sp_fraction * f, |
||||
|
struct scot_event_listener * e, |
||||
|
int s_type) |
||||
|
{ |
||||
|
f = SCOT_MEM_GET (sizeof (struct scot_sp_fraction)); |
||||
|
SCOT_MEM_ZERO (f, sizeof (struct scot_sp_fraction)); |
||||
|
|
||||
|
#ifdef WIN32 |
||||
|
f->Event = WSACreateEvent(); |
||||
|
#endif |
||||
|
|
||||
|
f->el = e; |
||||
|
f->stream_type = s_type; |
||||
|
f->spf_entry_func = scot_spf_thread_func[s_type]; |
||||
|
|
||||
|
return f; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_spf_set_free_streams (struct scot_sp_fraction * f, int free_s) |
||||
|
{ |
||||
|
f->free_s = free_s; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_spf_free (struct scot_sp_fraction * f) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
if (f->s_count != 0 && f->free_s != 0) |
||||
|
{ |
||||
|
for (i=0; i<SCOT_MAX_FRACTION; i++) |
||||
|
{ |
||||
|
if (f->s_list[i] != NULL) |
||||
|
SCOT_STREAM_FREE (f->s_list[i]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#ifdef WIN32 |
||||
|
WSACloseEvent(f->Event); |
||||
|
#endif |
||||
|
|
||||
|
SCOT_MEM_FREE (f); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_spf_free_s (struct scot_sp_fraction * f, int free_s) |
||||
|
{ |
||||
|
f->free_s = free_s; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_spf_add (struct scot_sp_fraction * spf, |
||||
|
struct scot_stream * s, |
||||
|
int rwe_mask) |
||||
|
{ |
||||
|
int i; |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
for (i = 0; spf->s_list [i] != NULL && i < SCOT_MAX_FRACTION; i++); |
||||
|
|
||||
|
if (i >= SCOT_MAX_FRACTION) |
||||
|
THROW (EXC (EXC_ERROR, 123, "fraction count < SCOT_MAX_FRACTION" |
||||
|
" but no element != NULL found")); |
||||
|
|
||||
|
spf->s_count ++; |
||||
|
spf->s_list [i] = s; |
||||
|
|
||||
|
scot_stream_set_nonblock (s); |
||||
|
|
||||
|
/* for select */ |
||||
|
if (s->handle.sock > spf->max_fd) |
||||
|
spf->max_fd = s->handle.sock; |
||||
|
if (rwe_mask & SCOT_STREAM_POOL_FD_ADD_RMASK) |
||||
|
FD_SET (s->handle.sock, &spf->rfds); |
||||
|
if (rwe_mask & SCOT_STREAM_POOL_FD_ADD_WMASK) |
||||
|
FD_SET (s->handle.sock, &spf->wfds); |
||||
|
if (rwe_mask & SCOT_STREAM_POOL_FD_ADD_EMASK) |
||||
|
FD_SET (s->handle.sock, &spf->efds); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
printf ("Exception in %s (%s, %d)\n", __FUNCTION__, __FILE__, __LINE__); |
||||
|
forward_all_exceptions (ee); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_spf_remove (struct scot_sp_fraction * spf, |
||||
|
struct scot_stream * s, |
||||
|
int rwe_mask) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
if (rwe_mask & SCOT_STREAM_POOL_FD_ADD_RMASK) |
||||
|
FD_CLR (s->handle.sock, &spf->rfds); |
||||
|
if (rwe_mask & SCOT_STREAM_POOL_FD_ADD_WMASK) |
||||
|
FD_CLR (s->handle.sock, &spf->wfds); |
||||
|
if (rwe_mask & SCOT_STREAM_POOL_FD_ADD_EMASK) |
||||
|
FD_CLR (s->handle.sock, &spf->efds); |
||||
|
|
||||
|
if (! FD_ISSET (s->handle.sock, &spf->rfds) && |
||||
|
! FD_ISSET (s->handle.sock, &spf->wfds) && |
||||
|
! FD_ISSET (s->handle.sock, &spf->efds)) |
||||
|
{ |
||||
|
spf->max_fd = 0; |
||||
|
|
||||
|
for (i=0; i<SCOT_MAX_FRACTION; i++) |
||||
|
{ |
||||
|
if (spf->s_list [i] == s) |
||||
|
{ |
||||
|
SCOT_MEM_MOVE ( |
||||
|
&(spf->s_list [i]), &(spf->s_list [i+1]), |
||||
|
(SCOT_MAX_FRACTION-i) * sizeof (struct scot_stream *)); |
||||
|
spf->s_list [SCOT_MAX_FRACTION-1-i] = NULL; |
||||
|
spf->s_count --; |
||||
|
} |
||||
|
|
||||
|
if (spf->s_list [i] != NULL && |
||||
|
spf->s_list [i]->handle.sock > spf->max_fd) |
||||
|
spf->max_fd = spf->s_list[i]->handle.sock; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,245 @@ |
|||||
|
#include <sys/types.h> |
||||
|
#include <unistd.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
#include <scot/stream_pool.h> |
||||
|
#include <scot/stream_pool_fraction.h> |
||||
|
|
||||
|
#include <scot/event_listener.h> |
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/stream.h> |
||||
|
#include <scot/memory.h> |
||||
|
#include <scot/thread.h> |
||||
|
|
||||
|
#define GEN_LOCAL |
||||
|
# include <scot/list.h> |
||||
|
#undef GEN_LOCAL |
||||
|
|
||||
|
GEN_LIST_FUNC_PROTO (scot_sp_fraction); |
||||
|
GEN_LIST_IMPL (scot_sp_fraction); |
||||
|
|
||||
|
/* |
||||
|
* static functions for this file |
||||
|
* ---------------------------------------------------------------------- |
||||
|
*/ |
||||
|
static |
||||
|
int |
||||
|
scot_get_free_spf_by_type (const struct scot_sp_fraction * a, |
||||
|
const struct scot_sp_fraction * b) |
||||
|
{ |
||||
|
if (a->stream_type != b->stream_type || |
||||
|
b->s_count >= SCOT_MAX_FRACTION) /* b ist der node bei find. */ |
||||
|
return -1; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
scot_get_spf_by_stream_handle (const struct scot_sp_fraction * a, |
||||
|
const struct scot_sp_fraction * b) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
for (i = 0; i < SCOT_MAX_FRACTION && b->s_list [i] != a->s_list [0]; i++); |
||||
|
if (i >= SCOT_MAX_FRACTION) |
||||
|
return -1; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
/* ---------------------------------------------------------------------- */ |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* Es wäre sicher auch schön eine Funktion zu haben, die einen Stream |
||||
|
* nach dem anderen (die in dem Stream Pool registriert sind)....oder aber |
||||
|
* eine komplette Liste aller in einem Pool registrierten Streams zurückgibt. |
||||
|
* So kann man bevor man einen StreamPool freigibt erstmal alle Streams |
||||
|
* rausholen (und evtl. auch freigeben.) |
||||
|
*/ |
||||
|
struct scot_stream * |
||||
|
scot_sp_get_all_streams (struct scot_stream_pool * sp) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* adds the given stream s->handle to the fd_set specified via |
||||
|
* rwe_mask. If the stream is not already under control of this |
||||
|
* stream pool it is added to s_list. Else only the flags within |
||||
|
* rfds, wfds and efds are updated. This function will never clean |
||||
|
* a flag, but only set them. |
||||
|
*/ |
||||
|
void |
||||
|
scot_stream_pool_add ( |
||||
|
struct scot_stream_pool * sp, |
||||
|
struct scot_stream * s, |
||||
|
int rwe_mask) |
||||
|
{ |
||||
|
struct scot_event_listener * l = (struct scot_event_listener *) sp; |
||||
|
struct scot_sp_fraction * f_search; |
||||
|
list_scot_sp_fraction_node_t * f_node; |
||||
|
struct scot_sp_fraction * f; |
||||
|
|
||||
|
/* |
||||
|
* soweit ich das in erinnerung habe sind meine listen nicht per se |
||||
|
* thread save. Daher sollte hier unbedingt noch ein mutex her, |
||||
|
* damit nicht gleichzeitig in die liste geschrieben (hier) |
||||
|
* und gelöscht wird (in remove) |
||||
|
*/ |
||||
|
LOCK_THREAD_MUTEX (&sp->mutex); |
||||
|
|
||||
|
/* |
||||
|
* it would be nice to check if the stream is already in the pool before |
||||
|
* doing anything else |
||||
|
*/ |
||||
|
|
||||
|
/* |
||||
|
* first seek a not full fraction for s->stream_type |
||||
|
*/ |
||||
|
f_search = scot_spf_new (f_search, l, s->s_type); |
||||
|
scot_spf_add (f_search, s, rwe_mask); |
||||
|
|
||||
|
list_scot_sp_fraction_set_cmp (scot_get_free_spf_by_type); |
||||
|
f_node = list_scot_sp_fraction_find (sp->pool, f_search); |
||||
|
list_scot_sp_fraction_set_cmp (list_scot_sp_fraction_default_cmp); |
||||
|
|
||||
|
if (f_node == NULL) |
||||
|
{ |
||||
|
f = f_search; |
||||
|
list_scot_sp_fraction_insert (sp->pool, f); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
scot_spf_free_s (f_search, SCOT_STREAM_POOL_KEEP_STREAMS); |
||||
|
scot_spf_free (f_search); |
||||
|
|
||||
|
f = list_scot_sp_fraction_retrive (f_node); |
||||
|
scot_spf_add (f, s, rwe_mask); |
||||
|
} |
||||
|
|
||||
|
scot_stream_pool_cmd (sp, SCOT_STREAM_POOL_RESTART_FRACTION, f); |
||||
|
|
||||
|
UNLOCK_THREAD_MUTEX (&sp->mutex); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* removes the given stream s->handle from the fd_set specified via |
||||
|
* rwe_mask. If the stream isn't left in at least one of the sets, either |
||||
|
* rfds, wfds or efds it is removed from s_list. This function will never |
||||
|
* set a flag, but the mask is used to determine where to remove fd. |
||||
|
* |
||||
|
* Diese Funktion und scot_stream_pool_add sollten sich gegenseitig |
||||
|
* ausschließen, um die liste immer in einem konsistenten zustand zu halten. |
||||
|
* Relevant sind da wohl nur threads, also sollte es ein thread_mutex tun. |
||||
|
*/ |
||||
|
void |
||||
|
scot_stream_pool_remove ( |
||||
|
struct scot_stream_pool * sp, |
||||
|
struct scot_stream * s, |
||||
|
int rwe_mask) |
||||
|
{ |
||||
|
struct scot_event_listener * l = (struct scot_event_listener *) sp; |
||||
|
struct scot_sp_fraction * f_search; |
||||
|
list_scot_sp_fraction_node_t * f_node; |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
LOCK_THREAD_MUTEX (&sp->mutex); |
||||
|
|
||||
|
/* |
||||
|
* first seek a not full fraction for s->stream_type |
||||
|
*/ |
||||
|
f_search = scot_spf_new (f_search, l, s->s_type); |
||||
|
scot_spf_add (f_search, s, rwe_mask); |
||||
|
|
||||
|
list_scot_sp_fraction_set_cmp (scot_get_spf_by_stream_handle); |
||||
|
f_node = list_scot_sp_fraction_find (sp->pool, f_search); |
||||
|
list_scot_sp_fraction_set_cmp (list_scot_sp_fraction_default_cmp); |
||||
|
|
||||
|
scot_spf_free (f_search); |
||||
|
|
||||
|
if (f_node == NULL) |
||||
|
THROW (EXC (EXC_ERROR, 345, "Can't find stream in any fraction.")); |
||||
|
else |
||||
|
{ |
||||
|
struct scot_sp_fraction * f; |
||||
|
|
||||
|
scot_stream_pool_cmd (sp, SCOT_STREAM_POOL_STOP_FRACTION, f); |
||||
|
|
||||
|
f = list_scot_sp_fraction_retrive (f_node); |
||||
|
scot_spf_remove (f, s, rwe_mask); |
||||
|
|
||||
|
scot_stream_pool_cmd (sp, SCOT_STREAM_POOL_START_FRACTION, f); |
||||
|
} |
||||
|
|
||||
|
UNLOCK_THREAD_MUTEX (&sp->mutex); |
||||
|
} |
||||
|
CATCH (ee) |
||||
|
{ |
||||
|
printf ("Exception in %s (%s, %d)\n", __FUNCTION__, __FILE__, __LINE__); |
||||
|
forward_all_exceptions (ee); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int /* rwe_mask */ |
||||
|
scot_stream_pool_get_rwe ( |
||||
|
struct scot_stream_pool * sp, |
||||
|
struct scot_stream * s) |
||||
|
{ |
||||
|
struct scot_event_listener * l = (struct scot_event_listener *) sp; |
||||
|
struct scot_sp_fraction * f_search; |
||||
|
list_scot_sp_fraction_node_t * f_node; |
||||
|
struct scot_sp_fraction * f; |
||||
|
int ret = 0; |
||||
|
excenv_t * ee; |
||||
|
|
||||
|
TRY |
||||
|
{ |
||||
|
f_search = scot_spf_new (f_search, l, s->s_type); |
||||
|
scot_spf_add (f_search, s, 0); |
||||
|
|
||||
|
list_scot_sp_fraction_set_cmp (scot_get_spf_by_stream_handle); |
||||
|
f_node = list_scot_sp_fraction_find (sp->pool, f_search); |
||||
|
list_scot_sp_fraction_set_cmp (list_scot_sp_fraction_default_cmp); |
||||
|
|
||||
|
scot_spf_free (f_search); |
||||
|
|
||||
|
if (f_node == NULL) |
||||
|
THROW (EXC (EXC_ERROR, 987, "could not find stream in stream pool")); |
||||
|
else |
||||
|
f = list_scot_sp_fraction_retrive (f_node); |
||||
|
|
||||
|
/* |
||||
|
* !!!FIXME!!! I will only work with sockets right now..... :-( |
||||
|
* Much more abstraction is in the stream code. |
||||
|
*/ |
||||
|
if (FD_ISSET (s->handle.sock, &f->rfds)) |
||||
|
ret = ret | SCOT_STREAM_POOL_FD_ADD_RMASK; |
||||
|
if (FD_ISSET (s->handle.sock, &f->wfds)) |
||||
|
ret = ret | SCOT_STREAM_POOL_FD_ADD_WMASK; |
||||
|
if (FD_ISSET (s->handle.sock, &f->efds)) |
||||
|
ret = ret | SCOT_STREAM_POOL_FD_ADD_EMASK; |
||||
|
} |
||||
|
CATCH (ee); |
||||
|
{ |
||||
|
printf ("Exception in %s (%s, %d)\n", __FUNCTION__, __FILE__, __LINE__); |
||||
|
forward_all_exceptions (ee); |
||||
|
} |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
scot_stream_pool_cmd (struct scot_stream_pool * sp, uint16_t cmd, void * arg) |
||||
|
{ |
||||
|
THREAD_COND_ENTER_CS (&sp->cmd_cs); |
||||
|
|
||||
|
sp->cmd = cmd; |
||||
|
sp->cmd_arg = arg; |
||||
|
SIGNAL_THREAD_COND (&sp->cmd_cond); |
||||
|
|
||||
|
THREAD_COND_LEAVE_CS (&sp->cmd_cs); |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,16 @@ |
|||||
|
#include <string.h> |
||||
|
|
||||
|
#include <scot/stream_win.h> |
||||
|
#include <scot/scot_int.h> |
||||
|
#include <scot/exception.h> |
||||
|
#include <scot/scot_types.h> |
||||
|
|
||||
|
SSIZE_T win_file_read (HANDLE h, void * buf, SIZE_T count) |
||||
|
{ |
||||
|
DWORD got = 0; |
||||
|
|
||||
|
if (ReadFile (h, buf, count, &got, NULL) == 0) |
||||
|
THROW (EXC (EXC_ERROR, GetLastError (), strerror (GetLastError ()))); |
||||
|
|
||||
|
return got; |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue