Browse Source

Initial repository layout

master
Georg Hopp 19 years ago
parent
commit
e35a763a91
  1. 0
      AUTHORS
  2. 51
      ChangeLog
  3. 27
      Makefile.am
  4. 65
      NEWS
  5. 0
      README
  6. 45
      autoclean.sh
  7. 15
      autogen.sh
  8. 168
      configure.ac
  9. BIN
      design/scot-event-subsystem.dia
  10. 102
      event_new.c
  11. 47
      include/Makefile.am
  12. 117
      include/scot/cmdla.h
  13. 26
      include/scot/dir_common.h
  14. 106
      include/scot/event.h
  15. 53
      include/scot/event_listener.h
  16. 52
      include/scot/excenv_t.h
  17. 133
      include/scot/exception.h
  18. 68
      include/scot/exception_t.h
  19. 47
      include/scot/fs_watcher.h
  20. 31
      include/scot/inotify.h
  21. 64
      include/scot/list.h
  22. 214
      include/scot/list_func_proto.h
  23. 252
      include/scot/list_impl.h
  24. 382
      include/scot/list_man.h
  25. 308
      include/scot/list_mod.h
  26. 290
      include/scot/list_nav.h
  27. 101
      include/scot/list_proto.h
  28. 64
      include/scot/list_type_proto.h
  29. 71
      include/scot/posix/dir.h
  30. 32
      include/scot/posix/memory.h
  31. 9
      include/scot/posix/scot_types.h
  32. 102
      include/scot/posix/thread.h
  33. 69
      include/scot/queue.h
  34. 89
      include/scot/queue_func_proto.h
  35. 241
      include/scot/queue_impl.h
  36. 68
      include/scot/queue_proto.h
  37. 61
      include/scot/queue_type_proto.h
  38. 19
      include/scot/scot_exceptions.h
  39. 85
      include/scot/socket.h
  40. 15
      include/scot/socket_in.h
  41. 14
      include/scot/socket_un.h
  42. 69
      include/scot/stack.h
  43. 89
      include/scot/stack_func_proto.h
  44. 239
      include/scot/stack_impl.h
  45. 68
      include/scot/stack_proto.h
  46. 61
      include/scot/stack_type_proto.h
  47. 132
      include/scot/stream.h
  48. 72
      include/scot/stream_pool.h
  49. 53
      include/scot/stream_pool_fraction.h
  50. 8
      include/scot/stream_win.h
  51. 51
      include/scot/thread_none.h
  52. 44
      include/scot/win32/dir.h
  53. 40
      include/scot/win32/memory.h
  54. 6
      include/scot/win32/scot_types.h
  55. 79
      include/scot/win32/thread.h
  56. 98
      include/scot_common.h
  57. 1
      m4/Makefile.am
  58. 685
      m4/ax_create_stdint_h.m4
  59. 61
      src/Makefile.am
  60. 408
      src/cmdla.c
  61. 348
      src/event.c
  62. 157
      src/event_listener.c
  63. 157
      src/event_manager.c
  64. 79
      src/event_subsys/event-subsys.txt
  65. 0
      src/event_subsys/scot_dispatch_manager.c
  66. 0
      src/event_subsys/scot_dispatcher.c
  67. 3
      src/event_subsys/scot_event_sink.c
  68. 0
      src/event_subsys/scot_event_typ.c
  69. 0
      src/event_subsys/scot_event_typ_GTK
  70. 0
      src/event_subsys/scot_event_typ_OPENGL
  71. 0
      src/event_subsys/scot_event_typ_SDL
  72. 0
      src/event_subsys/scot_event_typ_manager.c
  73. 0
      src/event_subsys/scot_event_typ_mswin.c
  74. 0
      src/event_subsys/scot_event_typ_xwin.c
  75. 868
      src/exception.c
  76. 416
      src/fs_watcher.c
  77. 340
      src/list.c
  78. 1
      src/po/LINGUAS
  79. 41
      src/po/Makevars
  80. 4
      src/po/POTFILES.in
  81. BIN
      src/po/de.gmo
  82. 171
      src/po/de.po
  83. 165
      src/po/scot.pot
  84. 1
      src/po/stamp-po
  85. 136
      src/posix/dir.c
  86. 133
      src/posix/spf_thread_impl.c
  87. 44
      src/posix/stream_ctl.c
  88. 169
      src/posix/thread.c
  89. 46
      src/queue.c
  90. 33
      src/scot_common.c
  91. 60
      src/scot_exceptions.c
  92. 184
      src/socket.c
  93. 200
      src/socket_in.c
  94. 149
      src/socket_un.c
  95. 47
      src/stack.c
  96. 189
      src/stream.c
  97. 328
      src/stream_pool_base.c
  98. 154
      src/stream_pool_fraction.c
  99. 245
      src/stream_pool_management.c
  100. 16
      src/stream_win.c

0
AUTHORS

51
ChangeLog

@ -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.

27
Makefile.am

@ -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

65
NEWS

@ -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
README

45
autoclean.sh

@ -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/*

15
autogen.sh

@ -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

168
configure.ac

@ -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

BIN
design/scot-event-subsystem.dia

102
event_new.c

@ -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
*/

47
include/Makefile.am

@ -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

117
include/scot/cmdla.h

@ -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 */

26
include/scot/dir_common.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 */

106
include/scot/event.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 */

53
include/scot/event_listener.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 */

52
include/scot/excenv_t.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 */

133
include/scot/exception.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 */

68
include/scot/exception_t.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 */

47
include/scot/fs_watcher.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 */

31
include/scot/inotify.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 */

64
include/scot/list.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 */

214
include/scot/list_func_proto.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 */

252
include/scot/list_impl.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 */

382
include/scot/list_man.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 */

308
include/scot/list_mod.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 */

290
include/scot/list_nav.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 */

101
include/scot/list_proto.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 */

64
include/scot/list_type_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 */

71
include/scot/posix/dir.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 */

32
include/scot/posix/memory.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 */

9
include/scot/posix/scot_types.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 */

102
include/scot/posix/thread.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 */

69
include/scot/queue.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 */

89
include/scot/queue_func_proto.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 */

241
include/scot/queue_impl.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 */

68
include/scot/queue_proto.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 */

61
include/scot/queue_type_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 */

19
include/scot/scot_exceptions.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 */

85
include/scot/socket.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 */

15
include/scot/socket_in.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 */

14
include/scot/socket_un.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 */

69
include/scot/stack.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 */

89
include/scot/stack_func_proto.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 */

239
include/scot/stack_impl.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 */

68
include/scot/stack_proto.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 */

61
include/scot/stack_type_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 */

132
include/scot/stream.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 */

72
include/scot/stream_pool.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 */

53
include/scot/stream_pool_fraction.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 */

8
include/scot/stream_win.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 */

51
include/scot/thread_none.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 */

44
include/scot/win32/dir.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 */

40
include/scot/win32/memory.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 */

6
include/scot/win32/scot_types.h

@ -0,0 +1,6 @@
#ifndef SCOT_TYPES_H
#define SCOT_TYPES_H
#include <Windows.h>
#endif /* SCOT_TYPES_H */

79
include/scot/win32/thread.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 */

98
include/scot_common.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 */

1
m4/Makefile.am

@ -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

685
m4/ax_create_stdint_h.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"
])
])

61
src/Makefile.am

@ -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

408
src/cmdla.c

@ -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;
}

348
src/event.c

@ -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;
}

157
src/event_listener.c

@ -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;
}
}
}

157
src/event_manager.c

@ -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);
}
}

79
src/event_subsys/event-subsys.txt

@ -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
src/event_subsys/scot_dispatch_manager.c

0
src/event_subsys/scot_dispatcher.c

3
src/event_subsys/scot_event_sink.c

@ -0,0 +1,3 @@
#include <scot_event_sink.h>
s

0
src/event_subsys/scot_event_typ.c

0
src/event_subsys/scot_event_typ_GTK

0
src/event_subsys/scot_event_typ_OPENGL

0
src/event_subsys/scot_event_typ_SDL

0
src/event_subsys/scot_event_typ_manager.c

0
src/event_subsys/scot_event_typ_mswin.c

0
src/event_subsys/scot_event_typ_xwin.c

868
src/exception.c

@ -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;
}

416
src/fs_watcher.c

@ -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);
}
}

340
src/list.c

@ -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);
}

1
src/po/LINGUAS

@ -0,0 +1 @@
de

41
src/po/Makevars

@ -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 =

4
src/po/POTFILES.in

@ -0,0 +1,4 @@
src/cmdla.c
src/list.c
src/stack.c
src/exception.c

BIN
src/po/de.gmo

171
src/po/de.po

@ -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"

165
src/po/scot.pot

@ -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 ""

1
src/po/stamp-po

@ -0,0 +1 @@
timestamp

136
src/posix/dir.c

@ -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;
}

133
src/posix/spf_thread_impl.c

@ -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 */
};

44
src/posix/stream_ctl.c

@ -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)));
}

169
src/posix/thread.c

@ -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);
}
}

46
src/queue.c

@ -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
};

33
src/scot_common.c

@ -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;
}

60
src/scot_exceptions.c

@ -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])));
}

184
src/socket.c

@ -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);
}
}

200
src/socket_in.c

@ -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
}

149
src/socket_un.c

@ -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);
}
}

47
src/stack.c

@ -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
};

189
src/stream.c

@ -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);
}

328
src/stream_pool_base.c

@ -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);
}
}

154
src/stream_pool_fraction.c

@ -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;
}
}
}

245
src/stream_pool_management.c

@ -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);
}

16
src/stream_win.c

@ -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

Loading…
Cancel
Save