SOLIB = libpnd.so.1 # canonicle name
SOLIB1 = libpnd.so.1.0.1 # versioned name
XMLOBJ = lib/tinyxml/tinystr.o lib/tinyxml/tinyxml.o lib/tinyxml/tinyxmlerror.o lib/tinyxml/tinyxmlparser.o
-ALLOBJ = pnd_conf.o pnd_container.o pnd_discovery.o pnd_pxml.o pnd_notify.o pnd_locate.o pnd_tinyxml.o pnd_pndfiles.o pnd_apps.o pnd_utility.o pnd_desktop.o pnd_io_gpio.o
+ALLOBJ = pnd_conf.o pnd_container.o pnd_discovery.o pnd_pxml.o pnd_notify.o pnd_locate.o pnd_tinyxml.o pnd_pndfiles.o pnd_apps.o pnd_utility.o pnd_desktop.o pnd_io_gpio.o pnd_logger.o
-all: ${SOLIB} ${LIB} conftest discotest notifytest pndnotifyd rawpxmltest pndvalidator
+all: ${SOLIB} ${LIB} conftest discotest notifytest pndnotifyd rawpxmltest pndvalidator loggertest
clean:
- ${RM} -f ${ALLOBJ} ${XMLOBJ} ${LIB} ${SOLIB1} locatetest.o bin/locatetest conftest.o bin/conftest discotest.o bin/discotest bin/notifytest notifytest.o bin/rawpxmltest rawpxmltest.o bin/pndnotifyd pndnotifyd.o ${SOLIB} testdata/dotdesktop/*.desktop testdata/apps/*.pnd testdata/dotdesktop/*.png deployment/usr/lib/libpnd* deployment/usr/bin/pndnotifyd deployment/usr/pandora/scripts/* deployment/etc/sudoers deployment/etc/init.d/pndnotifyd bin/pndvalidator pndvalidator.o
+ ${RM} -f ${ALLOBJ} ${XMLOBJ} ${LIB} ${SOLIB1} locatetest.o bin/locatetest conftest.o bin/conftest discotest.o bin/discotest loggertest.o bin/loggertest bin/notifytest notifytest.o bin/rawpxmltest rawpxmltest.o bin/pndnotifyd pndnotifyd.o ${SOLIB} testdata/dotdesktop/*.desktop testdata/apps/*.pnd testdata/dotdesktop/*.png deployment/usr/lib/libpnd* deployment/usr/bin/pndnotifyd deployment/usr/pandora/scripts/* deployment/etc/sudoers deployment/etc/init.d/pndnotifyd bin/pndvalidator pndvalidator.o
${RM} -rf deployment/media
find . -name "*~*" -exec rm {} \; -print
rawpxmltest: rawpxmltest.o ${LIB}
${CC} -lstdc++ -o bin/rawpxmltest rawpxmltest.o ${LIB}
+
+loggertest: loggertest.o ${LIB}
+ ${CC} -lstdc++ -o bin/loggertest loggertest.o libpnd.a
--- /dev/null
+
+#ifndef h_pnd_logger_h
+#define h_pnd_logger_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+/* rudimentary logger; note that this is meant to be a no-brainer to use, so no setup is needed.
+ */
+
+// defaults will have no filtering, so any message will be emitted to all targets
+// default target is nothing, however, so logger is silent unless activated
+unsigned char pnd_log ( unsigned char level, char *format, ... ); // returns true if emitted; \n is implied!
+unsigned char pnd_log_to_stdout ( void ); // same as pnd_log_to_stream ( stdout );
+unsigned char pnd_log_to_stderr ( void ); // same as pnd_log_to_stream ( stderr );
+
+/* the below is all optional, for when you need more control
+ */
+
+// logging is additive; you can log to multiple targets at once. Returns 'true' if accepted, false if could not set up.
+void pnd_log_to_nil ( void ); // stop logging to anywhere; does not close streams/etc
+unsigned char pnd_log_to_stream ( FILE * ); // 'stdout', 'stderr', or your own FILE* are good values
+unsigned char pnd_log_to_syslog ( char *facility ); // NYI
+typedef void (*pnd_log_callback_f)( char *text, void *userdata );
+unsigned char pnd_log_to_callback ( pnd_log_callback_f f, void *userdata ); // NYI
+
+// pass NULL to free any pre-text, otherwise it'll be kept. Passed in string is duplicated, so you may free yours if you like.
+void pnd_log_set_pretext ( char * ); // example: your app-name, or app+function-names, say.
+
+// set a 'filter level'; any log message of higher-or-equal level than current filter-level will be emitted. Thus, to remove filters
+// just set to level 0. Returns existing setting.
+unsigned char pnd_log_set_filter ( unsigned char newlevel ); // ex: app-specific enum/#defines for your levels
+
+// how many targets can be opened, entirely? this is a compile time limit, for sanity.
+unsigned char pnd_log_max_targets ( void );
+
+#ifdef __cplusplus
+} /* "C" */
+#endif
+
+#endif
--- /dev/null
+
+#include <stdarg.h> // va-args
+#include <stdlib.h> // malloc/free
+#include <string.h> // strdup
+#include "pnd_logger.h"
+
+char *log_pretext = NULL;
+unsigned char log_filterlevel = 0;
+
+typedef enum {
+ pndl_nil = 0,
+ pndl_stream,
+ pndl_syslog,
+ pndl_callback
+} pnd_logger_e;
+
+typedef struct {
+ pnd_logger_e type;
+ union {
+ FILE *stream;
+ pnd_log_callback_f callback;
+ };
+} pnd_log_target_t;
+
+#define PND_LOG_MAX 5
+static pnd_log_target_t log_targets [ PND_LOG_MAX ]; // implicitly nil
+
+static int pnd_log_empty_slot ( void ) {
+ unsigned char i;
+
+ for ( i = 0; i < PND_LOG_MAX; i++ ) {
+ if ( log_targets [ i ].type == pndl_nil ) {
+ return ( i );
+ }
+ }
+
+ return ( -1 );
+}
+
+unsigned char pnd_log_set_filter ( unsigned char newlevel ) {
+ unsigned char foo = log_filterlevel;
+ log_filterlevel = newlevel;
+ return ( foo );
+}
+
+void pnd_log_set_pretext ( char *pre ) {
+
+ if ( log_pretext ) {
+ free ( log_pretext );
+ log_pretext = NULL;
+ }
+
+ if ( pre ) {
+ log_pretext = strdup ( pre );
+ }
+
+ return;
+}
+
+void pnd_log_to_nil ( void ) {
+ memset ( log_targets, '\0', sizeof(pnd_log_target_t) * PND_LOG_MAX );
+ return;
+}
+
+unsigned char pnd_log_to_stream ( FILE *f ) {
+ int i = pnd_log_empty_slot();
+
+ if ( i < 0 ) {
+ return ( 0 ); // fail!
+ }
+
+ log_targets [ i ].type = pndl_stream;
+ log_targets [ i ].stream = f;
+
+ return ( 1 );
+}
+
+unsigned char pnd_log_to_syslog ( char *facility ) {
+ return ( 0 ); // NYI
+}
+
+unsigned char pnd_log_to_callback ( pnd_log_callback_f f, void *userdata ) {
+ return ( 0 ); // NYI
+}
+
+unsigned char pnd_log_to_stdout ( void ) {
+ return ( pnd_log_to_stream ( stdout ) );
+}
+
+unsigned char pnd_log_to_stderr ( void ) {
+ return ( pnd_log_to_stream ( stderr ) );
+}
+
+unsigned char pnd_log_max_targets ( void ) {
+ return ( PND_LOG_MAX );
+}
+
+void pnd_log_emit ( char *message ) {
+ unsigned char i;
+
+ // iterate across targets and attempt to emit
+ for ( i = 0; i < PND_LOG_MAX; i++ ) {
+
+ switch ( log_targets [ i ].type ) {
+
+ case pndl_nil:
+ // nop
+ break;
+
+ case pndl_stream:
+ if ( log_pretext ) {
+ fprintf ( log_targets [ i ].stream, "%s\t", log_pretext );
+ }
+ if ( message ) {
+ fprintf ( log_targets [ i ].stream, "%s\n", message );
+ }
+ break;
+
+ case pndl_syslog:
+ // NYI
+ break;
+
+ case pndl_callback:
+ // NYI
+ break;
+
+ } // switch
+
+ } // for
+
+ return;
+}
+
+unsigned char pnd_log ( unsigned char level, char *fmt, ... ) {
+
+ if ( level < log_filterlevel ) {
+ return ( 0 ); // too low level
+ }
+
+ // format the actual log string
+ int n, size = 100;
+ char *p, *np;
+ va_list ap;
+
+ if ( ( p = malloc ( size ) ) == NULL ) {
+ return ( 0 ); // fail!
+ }
+
+ while ( 1 ) {
+
+ /* Try to print in the allocated space. */
+ va_start ( ap, fmt );
+ n = vsnprintf ( p, size, fmt, ap );
+ va_end ( ap );
+
+ /* If that worked, return the string. */
+ if ( n > -1 && n < size ) {
+ pnd_log_emit ( p );
+ break;
+ }
+
+ /* Else try again with more space. */
+ if ( n > -1 ) /* glibc 2.1 */
+ size = n + 1; /* precisely what is needed */
+ else /* glibc 2.0 */
+ size *= 2; /* twice the old size */
+ if ( ( np = realloc ( p, size ) ) == NULL ) {
+ free(p);
+ return ( 0 ); // fail!
+ } else {
+ p = np;
+ }
+
+ } // while
+
+ if ( p ) {
+ free ( p );
+ }
+
+ return ( 1 );
+}
--- /dev/null
+
+#include "pnd_logger.h"
+
+// arbitrary warning level
+#define PLOG_LOW 0
+#define PLOG_MEDIUM 1
+#define PLOG_HIGH 2
+
+int main ( void ) {
+
+ pnd_log ( PLOG_LOW, "low message, should be ignored" );
+
+ /* normal operation -------------- */
+ pnd_log_to_stdout();
+ pnd_log ( PLOG_LOW, "low message, should go stdout once" );
+ /* ------------------------------- */
+
+ /* extra testing vvvvvvvvvvvvvvvvv
+ */
+
+ pnd_log_to_stdout();
+ pnd_log ( PLOG_LOW, "low message, should go stdout twice" );
+
+ pnd_log_to_nil();
+ pnd_log_to_stdout();
+
+ pnd_log_set_pretext ( "loggertest" );
+ pnd_log ( PLOG_LOW, "low message, emit once, with pretext" );
+
+ pnd_log_set_filter ( PLOG_MEDIUM );
+ pnd_log ( PLOG_LOW, "low message, emit once, filter is medium+" );
+ pnd_log ( PLOG_MEDIUM, "medium message, emit once, filter is medium+" );
+ pnd_log ( PLOG_HIGH, "high message, emit once, filter is medium+" );
+
+ pnd_log_set_filter ( PLOG_LOW );
+ pnd_log ( PLOG_LOW, "low message, emit once, filter is low+ again" );
+
+ return ( 0 );
+}