Logo Search packages:      
Sourcecode: uncrustify version File versions

logger.cpp

Go to the documentation of this file.
/**
 * @file logger.cpp
 *
 * Functions to do logging.
 *
 * If a log statement ends in a newline, the current log is ended.
 * When the log severity changes, an implicit newline is inserted.
 *
 * @author  Ben Gardner
 * @license GPL v2+
 *
 * $Id: logger.cpp 611 2006-12-20 04:12:46Z bengardner $
 */

#include "logger.h"

#include <cstdio>
#include <stdarg.h>
#include <cctype>


/** Private log structure */
00023 struct log_buf
{
   FILE       *log_file;
   log_sev_t  sev;
   int        in_log;
   char       buf[256];
   int        buf_len;
   log_mask_t mask;
   bool       show_hdr;
};
static struct log_buf g_log;


/**
 * Initializes the log subsystem - call this first.
 * This function sets the log stream and enables the top 3 sevs (0-2).
 *
 * @param log_file   NULL for stderr or the FILE stream for logs.
 */
00042 void log_init(FILE *log_file)
{
   memset(&g_log, 0, sizeof(g_log));

   /* set the top 3 severities */
   log_set_sev(0, true);
   log_set_sev(1, true);
   log_set_sev(2, true);

   g_log.log_file = (log_file != NULL) ? log_file : stderr;
}


/**
 * Show or hide the severity prefix "<1>"
 *
 * @param true=show  false=hide
 */
00060 void log_show_sev(bool show)
{
   g_log.show_hdr = show;
}


/**
 * Returns whether a log severity is active.
 *
 * @param sev  The severity
 * @return     true/false
 */
00072 bool log_sev_on(log_sev_t sev)
{
   return(logmask_test(&g_log.mask, sev));
}


/**
 * Sets a log sev on or off
 *
 * @param sev  The severity
 * @return     true/false
 */
00084 void log_set_sev(log_sev_t sev, bool value)
{
   logmask_set_sev(&g_log.mask, sev, value);
}


/**
 * Sets the log mask
 *
 * @param mask The mask to copy
 */
00095 void log_set_mask(const log_mask_t *mask)
{
   if (mask != NULL)
   {
      memcpy(g_log.mask.bits, mask->bits, sizeof(g_log.mask.bits));
   }
}


/**
 * Gets the log mask
 *
 * @param mask Where to copy the mask
 */
00109 void log_get_mask(log_mask_t *mask)
{
   if (mask != NULL)
   {
      memcpy(mask->bits, g_log.mask.bits, sizeof(g_log.mask.bits));
   }
}


/**
 * Flushes the cached log text to the stream
 *
 * @param force_nl   Append NL if not present
 */
00123 static void log_flush(bool force_nl)
{
   if (g_log.buf_len > 0)
   {
      if (force_nl && (g_log.buf[g_log.buf_len - 1] != '\n'))
      {
         g_log.buf[g_log.buf_len++] = '\n';
         g_log.buf[g_log.buf_len]   = 0;
      }
      (void)fwrite(g_log.buf, 1, g_log.buf_len, g_log.log_file);

      g_log.buf_len = 0;
   }
}


/**
 * Starts the log statment by flushing if needed and printing the header
 *
 * @param sev  The log severity
 */
00144 static void log_start(log_sev_t sev)
{
   if (sev != g_log.sev)
   {
      if (g_log.buf_len > 0)
      {
         log_flush(true);
      }
      g_log.sev    = sev;
      g_log.in_log = false;
   }

   if (!g_log.in_log)
   {
      /* Add the header, if enabled */
      if (g_log.show_hdr)
      {
         g_log.buf_len += snprintf(&g_log.buf[g_log.buf_len],
                                   sizeof(g_log.buf) - g_log.buf_len,
                                   "<%d>", sev);
      }
   }
}


/**
 * Cleans up after a log statement by detecting whether the log is done,
 * (it ends in a newline) and possibly flushing the log.
 */
00173 static void log_end(void)
{
   g_log.in_log = (g_log.buf[g_log.buf_len - 1] != '\n');
   if (!g_log.in_log || (g_log.buf_len > (int)(sizeof(g_log.buf) / 2)))
   {
      log_flush(false);
   }
}


/**
 * Logs a string of known length
 *
 * @param sev  The severity
 * @param str  The pointer to the string
 * @param len  The length of the string from strlen(str)
 */
00190 void log_str(log_sev_t sev, const char *str, int len)
{
   if ((str == NULL) || (len <= 0) || !log_sev_on(sev))
   {
      return;
   }

   if ((g_log.buf_len + len) < (int)sizeof(g_log.buf))
   {
      log_start(sev);

      memcpy(&g_log.buf[g_log.buf_len], str, len + 1);
      g_log.buf_len += len;

      log_end();
   }
}


/**
 * Logs a formatted string -- similiar to printf()
 *
 * @param sev     The severity
 * @param fmt     The format string
 * @param ...     Additional arguments
 */
00216 void log_fmt(log_sev_t sev, const char *fmt, ...)
{
   va_list args;

   if ((fmt == NULL) || !log_sev_on(sev))
   {
      return;
   }

   log_start(sev);

   /* Add on the variable log parameters to the log string */
   va_start(args, fmt);
   g_log.buf_len += vsnprintf(&g_log.buf[g_log.buf_len],
                              sizeof(g_log.buf) - g_log.buf_len,
                              fmt, args);
   va_end(args);

   log_end();
}


/**
 * Dumps hex characters inline, no newlines inserted
 *
 * @param sev     The severity
 * @param data    The data to log
 * @param len     The number of bytes to log
 */
00245 void log_hex(log_sev_t sev, const void *vdata, int len)
{
   const UINT8 *dat = (const UINT8 *)vdata;
   int         idx;
   char        buf[80];

   if ((vdata == NULL) || !log_sev_on(sev))
   {
      return;
   }

   idx = 0;
   while (len-- > 0)
   {
      buf[idx++] = to_hex_char(*dat >> 4);
      buf[idx++] = to_hex_char(*dat);
      dat++;

      if (idx >= (int)(sizeof(buf) - 3))
      {
         buf[idx] = 0;
         log_str(sev, buf, idx);
         idx = 0;
      }
   }

   if (idx > 0)
   {
      buf[idx] = 0;
      log_str(sev, buf, idx);
   }
}


/**
 * Logs a block of data in a pretty hex format
 * Numbers on the left, characters on the right, just like I like it.
 *
 * @param sev     The severity
 * @param data    The data to log
 * @param len     The number of bytes to log
 */
00287 void log_hex_blk(log_sev_t sev, const void *data, int len)
{
   static char buf[80] = "nnn | XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX | cccccccccccccccc\n";
   const UINT8 *dat    = (const UINT8 *)data;
   int         idx;
   int         count;
   int         str_idx = 0;
   int         chr_idx = 0;
   int         tmp;
   int         total;

   if ((data == NULL) || (len <= 0) || !log_sev_on(sev))
   {
      return;
   }

   /*
    * Dump the specified number of bytes in hex, 16 byte per line by
    * creating a string and then calling log_str()
    */

   /* Loop through the data of the current iov */
   count = 0;
   total = 0;
   for (idx = 0; idx < len; idx++)
   {
      if (count == 0)
      {
         str_idx = 6;
         chr_idx = 56;

         buf[0] = to_hex_char(total >> 12);
         buf[1] = to_hex_char(total >> 8);
         buf[2] = to_hex_char(total >> 4);
      }

      tmp = dat[idx];

      buf[str_idx]     = to_hex_char(tmp >> 4);
      buf[str_idx + 1] = to_hex_char(tmp);
      str_idx         += 3;

      buf[chr_idx++] = isprint(tmp) ? tmp : '.';

      total++;
      count++;
      if (count >= 16)
      {
         count = 0;
         log_str(sev, buf, 73);
      }
   }

   /*
   ** Print partial line if any
   */
   if (count != 0)
   {
      /* Clear out any junk */
      while (count < 16)
      {
         buf[str_idx]     = ' ';   /* MSB hex */
         buf[str_idx + 1] = ' ';   /* LSB hex */
         str_idx         += 3;

         buf[chr_idx++] = ' ';

         count++;
      }
      log_str(sev, buf, 73);
   }
}

Generated by  Doxygen 1.6.0   Back to index