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