Ejemplo n.º 1
0
/* Clean up any temporary directory.  Designed for use as an atexit
   handler, where it is not safe to call exit() recursively; so this
   calls _exit if a problem is encountered.  */
static void
cleanup_tmpfile (void)
{
  /* Close any open diversions.  */
  bool fail = false;

  if (diversion_table)
    {
      const void *elt;
      gl_oset_iterator_t iter = gl_oset_iterator (diversion_table);
      while (gl_oset_iterator_next (&iter, &elt))
        {
          m4_diversion *diversion = (m4_diversion *) elt;
          if (!diversion->size && diversion->u.file
              && close_stream_temp (diversion->u.file) != 0)
            {
              M4ERROR ((0, errno,
                        "cannot clean temporary file for diversion"));
              fail = true;
            }
        }
      gl_oset_iterator_free (&iter);
    }

  /* Clean up the temporary directory.  */
  if (cleanup_temp_dir (output_temp_dir) != 0)
    fail = true;
  if (fail)
    _exit (exit_failure);
}
Ejemplo n.º 2
0
static void
check_equals (gl_oset_t set1, gl_oset_t set2)
{
  size_t n = gl_oset_size (set1);
  gl_oset_iterator_t iter1, iter2;
  const void *elt1;
  const void *elt2;
  size_t i;

  iter1 = gl_oset_iterator (set1);
  iter2 = gl_oset_iterator (set2);
  for (i = 0; i < n; i++)
    {
      ASSERT (gl_oset_iterator_next (&iter1, &elt1));
      ASSERT (gl_oset_iterator_next (&iter2, &elt2));
      ASSERT (elt1 == elt2);
    }
  ASSERT (!gl_oset_iterator_next (&iter1, &elt1));
  ASSERT (!gl_oset_iterator_next (&iter2, &elt2));
  gl_oset_iterator_free (&iter1);
  gl_oset_iterator_free (&iter2);
}
Ejemplo n.º 3
0
void
undivert_all (void)
{
  const void *elt;
  gl_oset_iterator_t iter = gl_oset_iterator (diversion_table);
  while (gl_oset_iterator_next (&iter, &elt))
    {
      m4_diversion *diversion = (m4_diversion *) elt;
      if (diversion->divnum != current_diversion)
        insert_diversion_helper (diversion);
    }
  gl_oset_iterator_free (&iter);
}
Ejemplo n.º 4
0
void
freeze_diversions (FILE *file)
{
  int saved_number;
  int last_inserted;
  gl_oset_iterator_t iter;
  const void *elt;

  saved_number = current_diversion;
  last_inserted = 0;
  make_diversion (0);
  output_file = file; /* kludge in the frozen file */

  iter = gl_oset_iterator (diversion_table);
  while (gl_oset_iterator_next (&iter, &elt))
    {
      m4_diversion *diversion = (m4_diversion *) elt;
      if (diversion->size || diversion->used)
        {
          if (diversion->size)
            xfprintf (file, "D%d,%d\n", diversion->divnum, diversion->used);
          else
            {
              struct stat file_stat;
              diversion->u.file = m4_tmpopen (diversion->divnum, true);
              if (fstat (fileno (diversion->u.file), &file_stat) < 0)
                M4ERROR ((EXIT_FAILURE, errno, "cannot stat diversion"));
              if (file_stat.st_size < 0
                  || (file_stat.st_size + 0UL
                      != (unsigned long int) file_stat.st_size))
                M4ERROR ((EXIT_FAILURE, 0, "diversion too large"));
              xfprintf (file, "D%d,%lu\n", diversion->divnum,
                        (unsigned long int) file_stat.st_size);
            }

          insert_diversion_helper (diversion);
          putc ('\n', file);

          last_inserted = diversion->divnum;
        }
    }
  gl_oset_iterator_free (&iter);

  /* Save the active diversion number, if not already.  */

  if (saved_number != last_inserted)
    xfprintf (file, "D%d,0\n\n", saved_number);
}
Ejemplo n.º 5
0
static void
make_room_for (int length)
{
  int wanted_size;
  m4_diversion *selected_diversion = NULL;

  /* Compute needed size for in-memory buffer.  Diversions in-memory
     buffers start at 0 bytes, then 512, then keep doubling until it is
     decided to flush them to disk.  */

  output_diversion->used = output_diversion->size - output_unused;

  for (wanted_size = output_diversion->size;
       wanted_size < output_diversion->used + length;
       wanted_size = wanted_size == 0 ? INITIAL_BUFFER_SIZE : wanted_size * 2)
    ;

  /* Check if we are exceeding the maximum amount of buffer memory.  */

  if (total_buffer_size - output_diversion->size + wanted_size
      > MAXIMUM_TOTAL_SIZE)
    {
      int selected_used;
      char *selected_buffer;
      m4_diversion *diversion;
      int count;
      gl_oset_iterator_t iter;
      const void *elt;

      /* Find out the buffer having most data, in view of flushing it to
         disk.  Fake the current buffer as having already received the
         projected data, while making the selection.  So, if it is
         selected indeed, we will flush it smaller, before it grows.  */

      selected_diversion = output_diversion;
      selected_used = output_diversion->used + length;

      iter = gl_oset_iterator (diversion_table);
      while (gl_oset_iterator_next (&iter, &elt))
        {
          diversion = (m4_diversion *) elt;
          if (diversion->used > selected_used)
            {
              selected_diversion = diversion;
              selected_used = diversion->used;
            }
        }
      gl_oset_iterator_free (&iter);

      /* Create a temporary file, write the in-memory buffer of the
         diversion to this file, then release the buffer.  Zero the
         diversion before doing anything that can exit () (including
         m4_tmpfile), so that the atexit handler doesn't try to close
         a garbage pointer as a file.  */

      selected_buffer = selected_diversion->u.buffer;
      total_buffer_size -= selected_diversion->size;
      selected_diversion->size = 0;
      selected_diversion->u.file = NULL;
      selected_diversion->u.file = m4_tmpfile (selected_diversion->divnum);

      if (selected_diversion->used > 0)
        {
          count = fwrite (selected_buffer, (size_t) selected_diversion->used,
                          1, selected_diversion->u.file);
          if (count != 1)
            M4ERROR ((EXIT_FAILURE, errno,
                      "ERROR: cannot flush diversion to temporary file"));
        }

      /* Reclaim the buffer space for other diversions.  */

      free (selected_buffer);
      selected_diversion->used = 1;
    }

  /* Reload output_file, just in case the flushed diversion was current.  */

  if (output_diversion == selected_diversion)
    {
      /* The flushed diversion was current indeed.  */

      output_file = output_diversion->u.file;
      output_cursor = NULL;
      output_unused = 0;
    }
  else
    {
      /* Close any selected file since it is not the current diversion.  */
      if (selected_diversion)
        {
          FILE *file = selected_diversion->u.file;
          selected_diversion->u.file = NULL;
          if (m4_tmpclose (file, selected_diversion->divnum) != 0)
            m4_error (0, errno,
                      _("cannot close temporary file for diversion"));
        }

      /* The current buffer may be safely reallocated.  */
      {
        char *buffer = output_diversion->u.buffer;
        output_diversion->u.buffer = xcharalloc ((size_t) wanted_size);
        memcpy (output_diversion->u.buffer, buffer, output_diversion->used);
        free (buffer);
      }

      total_buffer_size += wanted_size - output_diversion->size;
      output_diversion->size = wanted_size;

      output_cursor = output_diversion->u.buffer + output_diversion->used;
      output_unused = wanted_size - output_diversion->used;
    }
}