--- /dev/null
- static char * unspecified_funct = (char*)"???";
+/**
+ * @file log.c
+ * @purpose Implement logging and error handling functions
+ */
+
+
+#include <unistd.h>
+
+// --- Custom headers --- //
+#include "log.h"
+#include "options.h"
+
+// --- Static variables --- //
- void Log(int level, char * funct, char * fmt, ...)
++static const char * unspecified_funct = "???";
+
+// --- Function implementations --- //
+
+/**
+ * Print a message to stderr
+ * @param level - Specify how severe the message is.
+ If level is higher (less urgent) than the program's verbosity (see options.h) no message will be printed
+ * @param funct - String indicating the function name from which this function was called.
+ If this is NULL, Log will show the unspecified_funct string instead
+ * @param fmt - A format string
+ * @param ... - Arguments to be printed according to the format string
+ */
- Fatal("Log", "Format string is NULL");
++void LogEx(int level, const char * funct, ...)
+{
++ const char *fmt;
++ va_list va;
++ va_start(va, funct);
++ fmt = va_arg(va, const char*);
++
+ if (fmt == NULL) // sanity check
- if (level > g_options.verbosity)
++ FatalEx("Log", "Format string is NULL");
+
+ // Don't print the message unless we need to
- char severity[BUFSIZ];
++ if (level > g_options.verbosity)
+ return;
+
+ if (funct == NULL)
+ funct = unspecified_funct;
+
+ // Make a human readable severity string
- sprintf(severity, "ERROR");
++ const char *severity;
+ switch (level)
+ {
+ case LOGERR:
- sprintf(severity, "WARNING");
++ severity = "ERROR";
+ break;
+ case LOGWARN:
- sprintf(severity, "NOTICE");
++ severity = "WARNING";
+ break;
+ case LOGNOTE:
- sprintf(severity, "INFO");
++ severity = "NOTICE";
+ break;
+ case LOGINFO:
- sprintf(severity, "DEBUG");
++ severity = "INFO";
+ break;
+ default:
- va_list va;
- va_start(va, fmt);
++ severity = "DEBUG";
+ break;
+ }
+
+ // Print: Program name, PID, severity string, function name first
+ fprintf(stderr, "%s [%d] : %s : %s - ", g_options.program, getpid(), severity, funct);
+
+ // Then pass additional arguments with the format string to vfprintf for printing
- CALLING THIS FUNCTION WILL CAUSE THE PROGAM TO EXIT
+ vfprintf(stderr, fmt, va);
+ va_end(va);
+
+ // End log messages with a newline
+ fprintf(stderr, "\n");
+}
+
+/**
+ * Handle a Fatal error in the program by printing a message and exiting the program
- void Fatal(char * funct, char * fmt, ...)
++ * CALLING THIS FUNCTION WILL CAUSE THE PROGAM TO EXIT
+ * @param funct - Name of the calling function
+ * @param fmt - A format string
+ * @param ... - Arguments to be printed according to the format string
+ */
- Fatal("Fatal", "Format string is NULL");
++void FatalEx(const char * funct, ...)
+{
++ const char *fmt;
++ va_list va;
++ va_start(va, funct);
++ fmt = va_arg(va, const char*);
+
+ if (fmt == NULL)
+ {
+ // Fatal error in the Fatal function.
+ // (This really shouldn't happen unless someone does something insanely stupid)
- va_list va;
- va_start(va, fmt);
++ FatalEx("Fatal", "Format string is NULL");
+ return; // Should never get here
+ }
+
+ if (funct == NULL)
+ funct = unspecified_funct;
+
+ fprintf(stderr, "%s [%d] : %s : FATAL - ", g_options.program, getpid(), funct);
+
+ vfprintf(stderr, fmt, va);
+ va_end(va);
+ fprintf(stderr, "\n");
+
+ exit(EXIT_FAILURE);
+}
+
+
--- /dev/null
- extern void Log(int level, char * funct, char * fmt,...); // General function for printing log messages to stderr
- extern void Fatal(char * funct, char * fmt, ...); // Function that deals with a fatal error (prints a message, then exits the program).
+/**
+ * @file log.h
+ * @purpose Declaration of functions for printing log messages and/or terminating program after a fatal error
+ */
+
+#ifndef _LOG_H
+#define _LOG_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
++//To get around a 'pedantic' C99 rule that you must have at least 1 variadic arg, combine fmt into that.
++#define Log(level, ...) LogEx(level, __func__, __VA_ARGS__)
++#define Fatal(...) FatalEx(__func__, __VA_ARGS__)
+
+// An enum to make the severity of log messages human readable in code
+enum {LOGERR=0, LOGWARN=1, LOGNOTE=2, LOGINFO=3,LOGDEBUG=4};
+
++extern void LogEx(int level, const char * funct, ...); // General function for printing log messages to stderr
++extern void FatalEx(const char * funct, ...); // Function that deals with a fatal error (prints a message, then exits the program).
+
+#endif //_LOG_H
+
+//EOF
--- /dev/null
- Log(LOGDEBUG, "ParseArguments", "Called as %s with %d arguments.", g_options.program, argc);
+/**
+ * @file main.c
+ * @purpose main and its helper functions, signal handling and cleanup functions
+ */
+
+#define _POSIX_C_SOURCE 200809L // For strsignal to work
+
+// --- Standard headers --- //
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h> // for signal handling
+#include <string.h> // string functions
+#include <pthread.h>
+
+// --- Custom headers --- //
+#include "log.h"
+#include "options.h"
+
+// --- Variable definitions --- //
+Options g_options; // options passed to program through command line arguments
+
+// --- Function definitions --- //
+
+/**
+ * Parse command line arguments, initialise g_options
+ * @param argc - Number of arguments
+ * @param argv - Array of argument strings
+ */
+void ParseArguments(int argc, char ** argv)
+{
+ g_options.program = argv[0]; // program name
+ g_options.verbosity = LOGDEBUG; // default log level
- Log(LOGWARN, "SignalHandler", "Got signal %d (%s). Exiting.", signal, strsignal(signal));
++ Log(LOGDEBUG, "Called as %s with %d arguments.", g_options.program, argc);
+}
+
+/**
+ * Handle a signal
+ * @param signal - The signal number
+ */
+void SignalHandler(int signal)
+{
+ // At the moment just always exit.
+ // Call `exit` so that Cleanup will be called to... clean up.
- Log(LOGDEBUG, "Cleanup", "Begin cleanup.");
- Log(LOGDEBUG, "Cleanup", "Finish cleanup.");
++ Log(LOGWARN, "Got signal %d (%s). Exiting.", sig, strsignal(sig));
+ exit(sig);
+}
+
+/**
+ * Cleanup before the program exits
+ */
+void Cleanup()
+{
++ Log(LOGDEBUG, "Begin cleanup.");
++ Log(LOGDEBUG, "Finish cleanup.");
+
+}
+
+/**
+ * Main entry point; start worker threads, setup signal handling, wait for threads to exit, exit
+ * @param argc - Num args
+ * @param argv - Args
+ * @returns 0 on success, error code on failure
+ */
+int main(int argc, char ** argv)
+{
++ ParseArguments(argc, argv, &g_options);
+ return 0;
+}
+
+