Logo Search packages:      
Sourcecode: nagircbot version File versions  Download package

br.cpp

/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */

#define _LARGEFILE64_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <syslog.h>
#include "br.h"

buffered_reader::buffered_reader(int cur_fd, int cur_block_size)
{
#ifdef USE_MMAP
      struct stat64 finfo;
#endif

      fd = cur_fd;
      block_size = cur_block_size;
      buffer = NULL;
      buffer_length = buffer_pointer = 0;
      mmap_addr = NULL;

      /* try do mmap */
#ifdef USE_MMAP
      if (fstat64(cur_fd, &finfo) == 0)
      {
            if (!S_ISFIFO(finfo.st_mode))
            {
                  /* mmap */
                  size_of_file = finfo.st_size;
                  cur_offset = mmap_addr = (char *)mmap64(NULL, size_of_file, PROT_READ, MAP_SHARED, cur_fd, 0);
                  if (!mmap_addr)
                  {
                        fprintf(stderr, "mmap64 failed: %d/%s\n", errno, strerror(errno));
                  }

                  /* advise the kernel how to treat the mmaped region */
                  /* FIXME: change to madvise64 as soon as it comes available */
                  (void)madvise(mmap_addr, size_of_file, MADV_SEQUENTIAL);

                  // fprintf(stderr, "*using mmap*\n");
            }
      }
      else
      {
            fprintf(stderr, "Error obtaining information on fd %d: %d/%s\n", cur_fd, errno, strerror(errno));
      }
#endif

      if (!mmap_addr)
      {
#if (_XOPEN_VERSION >= 600)
            (void)posix_fadvise(cur_fd, 0, 0, POSIX_FADV_SEQUENTIAL); // or POSIX_FADV_NOREUSE?
#endif
      }
}

buffered_reader::~buffered_reader()
{
      free(buffer);

      if (mmap_addr)
            munmap(mmap_addr, size_of_file);
}

int buffered_reader::number_of_bytes_in_buffer(void)
{
      return buffer_length - buffer_pointer;
}

int buffered_reader::garbage_collect(char shrink_buffer)
{
      if (buffer_pointer)
      {
            int n_to_move = number_of_bytes_in_buffer();

            if (n_to_move > 0)
            {
                  memmove(&buffer[0], &buffer[buffer_pointer], n_to_move);
                  buffer_length -= buffer_pointer;
                  buffer_pointer = 0;

                  if (shrink_buffer)
                  {
                        char *dummy = (char *)realloc(buffer, buffer_length + 1);
                        if (!dummy)
                        {
                              fprintf(stderr, "buffered_reader::garbage_collect: realloc failed\n");
                              syslog(LOG_EMERG, "buffered_reader::garbage_collect: realloc failed");
                              exit(1);
                        }

                        buffer = dummy;
                  }
                  buffer[buffer_length] = 0x00;
            }
      }

      return 0;
}

int buffered_reader::read_into_buffer(void)
{
      char *dummy;
      int n_read = 0;

      garbage_collect();

      dummy = (char *)realloc(buffer, buffer_length + block_size + 1);
      if (!dummy)
      {
            fprintf(stderr, "buffered_reader::read_into_buffer: realloc failed\n");
            syslog(LOG_EMERG, "buffered_reader::read_into_buffer: realloc failed");
            exit(1);
      }
      buffer = dummy;

      for(;;)
      {
            n_read = read(fd, &buffer[buffer_length], block_size);

            if (n_read == -1)
            {
                  if (errno == EINTR || errno == EAGAIN)
                        continue;

                  fprintf(stderr, "buffered_reader::read_into_buffer: read failed (%s)\n", strerror(errno));
                  syslog(LOG_EMERG, "buffered_reader::read_into_buffer: read failed: %m");
                  exit(1);
            }

            buffer_length += n_read;

            break;
      }
      buffer[buffer_length] = 0x00;

      return n_read;
}

char * buffered_reader::read_line(void)
{
      char *out = NULL;

#ifdef USE_MMAP
      if (mmap_addr)
      {
            long long int n_bytes;
            char *lf;
            char *virtual_0x00 = &mmap_addr[size_of_file];

            /* EOF reached? */
            if (!cur_offset)
                  return NULL;

            /* determine length of current line */
            lf = (char *)memchr(cur_offset, '\n', (virtual_0x00 - cur_offset));

            if (lf)
                  n_bytes = lf - cur_offset;
            else
                  n_bytes = virtual_0x00 - cur_offset;

            /* allocate memory & copy string */
            out = (char *)malloc(n_bytes + 1);
            if (!out)
            {
                  fprintf(stderr, "buffered_reader::read_line: malloc(%lld) failed\n", n_bytes + 1);
                  syslog(LOG_EMERG, "buffered_reader::read_line: malloc(%lld) failed", n_bytes + 1);
                  exit(1);
            }

            memcpy(out, cur_offset, n_bytes);
            out[n_bytes] = 0x00;

            if (lf)
                  cur_offset = lf + 1;
            else
                  cur_offset = NULL;
      }
      else
#endif
      {
            long long int lf_offset = -1;
            long long int n_bytes, search_start;

            if (number_of_bytes_in_buffer() <= 0)
            {
                  garbage_collect();

                  if (read_into_buffer() == 0)
                  {
                        // EOF
                        return NULL;
                  }
            }

            search_start = buffer_pointer;

            for(;;)
            {
                  char *dummy = strchr(&buffer[buffer_pointer], '\n');
                  if (dummy)
                        lf_offset = (long long int)(dummy - buffer);

                  if (lf_offset != -1)
                        break;

                  if (read_into_buffer() == 0)
                  {
                        lf_offset = buffer_length;
                        break;
                  }
            }

            n_bytes = lf_offset - buffer_pointer;

            out = strndup(&buffer[buffer_pointer], n_bytes);
            if (!out)
            {
                  fprintf(stderr, "buffered_reader::read_line: malloc(%lld) failed\n", n_bytes + 1);
                  syslog(LOG_EMERG, "buffered_reader::read_line: malloc(%lld) failed", n_bytes + 1);
                  exit(1);
            }

            buffer_pointer = lf_offset + 1;
      }

      return out;
}

off64_t buffered_reader::file_offset(void)
{
      if (mmap_addr)
            return cur_offset - mmap_addr;
      else
            return lseek64(fd, 0, SEEK_CUR);
}

Generated by  Doxygen 1.6.0   Back to index