#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "gsklogringbuffer.h"
struct _GskLogRingBuffer
{
guint buffer_alloced;
char *buffer;
guint read_pos, amount_buffered;
};
GskLogRingBuffer *gsk_log_ring_buffer_new (gsize size)
{
GskLogRingBuffer *rv = g_new (GskLogRingBuffer, 1);
rv->buffer_alloced = size;
rv->buffer = g_malloc (size);
rv->read_pos = rv->amount_buffered = 0;
return rv;
}
void gsk_log_ring_buffer_add (GskLogRingBuffer *buffer,
const char *line)
{
guint line_len = strlen (line);
guint clamped_line_len = MIN (line_len, buffer->buffer_alloced / 2);
guint app_len = clamped_line_len + 1;
guint write_pos;
while (buffer->amount_buffered + app_len > buffer->buffer_alloced)
{
/* remove oldest line */
guint line_len;
if (buffer->read_pos + buffer->amount_buffered > buffer->buffer_alloced)
{
guint p1 = buffer->buffer_alloced - buffer->read_pos;
char *s1 = buffer->buffer + buffer->read_pos;
guint p2 = buffer->amount_buffered - p1;
char *s2 = buffer->buffer;
char *found = memchr (s1, '\n', p1);
if (found)
line_len = found - s1;
else
{
found = memchr (s2, '\n', p2);
g_assert (found);
line_len = (found - s2) + p1;
}
}
else
{
char *found = memchr (buffer->buffer + buffer->read_pos,
'\n', buffer->amount_buffered);
g_assert (found);
line_len = found - (buffer->buffer + buffer->read_pos);
}
/* include newline in line length */
line_len += 1;
/* remove the line from the start of the buffer */
buffer->read_pos += line_len;
if (buffer->read_pos >= buffer->buffer_alloced)
buffer->read_pos -= buffer->buffer_alloced;
buffer->amount_buffered -= line_len;
}
write_pos = buffer->amount_buffered + buffer->read_pos;
if (write_pos >= buffer->buffer_alloced)
write_pos -= buffer->buffer_alloced;
if (write_pos + clamped_line_len > buffer->buffer_alloced)
{
guint p1 = buffer->buffer_alloced - write_pos;
guint p2 = clamped_line_len - p1;
memcpy (buffer->buffer + write_pos, line, p1);
memcpy (buffer->buffer, line + p1, p2);
write_pos = p2;
}
else if (write_pos + clamped_line_len == buffer->buffer_alloced)
{
memcpy (buffer->buffer + write_pos, line,
clamped_line_len);
write_pos = 0;
}
else
{
memcpy (buffer->buffer + write_pos, line, clamped_line_len);
write_pos += clamped_line_len;
}
g_assert (write_pos < buffer->buffer_alloced);
buffer->buffer[write_pos] = '\n';
buffer->amount_buffered += app_len;
}
char *
gsk_log_ring_buffer_get (const GskLogRingBuffer *buffer)
{
char *rv = g_malloc (buffer->amount_buffered + 1);
if (buffer->amount_buffered + buffer->read_pos > buffer->buffer_alloced)
{
guint p1 = buffer->buffer_alloced - buffer->read_pos;
guint p2 = buffer->amount_buffered - p1;
memcpy (rv, buffer->buffer + buffer->read_pos, p1);
memcpy (rv + p1, buffer->buffer, p2);
}
else
{
memcpy (rv, buffer->buffer + buffer->read_pos, buffer->amount_buffered);
}
rv[buffer->amount_buffered] = 0;
return rv;
}
char *
gsk_substitute_localtime_in_string (const char *str,
const char *strftime_format)
{
GString *rv = g_string_new ("");
char date_buffer[256];
char num_buffer[16];
time_t last_t = 0;
if (strftime_format == NULL)
strftime_format = "%Y%m%d %k:%M:%S";
while (*str)
{
const char *endline = strchr (str, '\n');
const char *endnum = str + strspn (str, G_CSET_DIGITS);
time_t t;
struct tm tm;
if (endline == NULL)
break;
if (endnum == str || (gint)(endnum-str) > (gint)(sizeof(num_buffer)-1))
{
endnum = str;
goto pass_line;
}
memcpy (num_buffer, str, endnum - str);
num_buffer[endnum - str] = 0;
t = strtol (num_buffer, NULL, 10);
if (t != last_t)
{
localtime_r (&t, &tm);
last_t = t;
}
strftime (date_buffer, sizeof (date_buffer),
strftime_format, &tm);
g_string_append (rv, date_buffer);
pass_line:
g_string_append_len (rv, endnum, endline - endnum + 1);
str = endline + 1; /* skip the newline */
}
return g_string_free (rv, FALSE);
}
void gsk_log_ring_buffer_free(GskLogRingBuffer *buffer)
{
g_free (buffer->buffer);
g_free (buffer);
}
syntax highlighted by Code2HTML, v. 0.9.1