cpppch.c   [plain text]


/* Part of CPP library.  (Precompiled header reading/writing.)
   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include "config.h"
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
#include "intl.h"
#include "hashtab.h"
#include "mkdeps.h"

static int write_macdef PARAMS ((cpp_reader *, cpp_hashnode *, void *));
static int save_idents PARAMS ((cpp_reader *, cpp_hashnode *, void *));
static hashval_t hashmem PARAMS ((const void *, size_t));
static hashval_t cpp_string_hash PARAMS ((const void *));
static int cpp_string_eq PARAMS ((const void *, const void *));
static int count_defs PARAMS ((cpp_reader *, cpp_hashnode *, void *));
/* APPLE LOCAL begin speed up pch validation */
static int comp_hashnodes PARAMS ((const void *, const void *));
static int collect_ht_nodes PARAMS ((cpp_reader *, cpp_hashnode *, void *));
/* APPLE LOCAL end speed up pch validation */
static int write_defs PARAMS ((cpp_reader *, cpp_hashnode *, void *));
static int save_macros PARAMS ((cpp_reader *, cpp_hashnode *, void *));
/* APPLE LOCAL begin speed up pch reading */
/* Removed declaration of reset_ht. */
/* APPLE LOCAL end speed up pch reading */

/* This structure represents a macro definition on disk.  */
struct macrodef_struct 
{
  unsigned int definition_length;
  unsigned short name_length;
  unsigned short flags;
};

/* This is how we write out a macro definition.  
   Suitable for being called by cpp_forall_identifiers.  */

static int
write_macdef (pfile, hn, file_p)
     cpp_reader *pfile;
     cpp_hashnode *hn;
     void *file_p;
{
  FILE *f = (FILE *) file_p;
  switch (hn->type)
    {
    case NT_VOID:
      if (! (hn->flags & NODE_POISONED))
	return 1;
      
    case NT_MACRO:
      if ((hn->flags & NODE_BUILTIN))
	return 1;

      {
	struct macrodef_struct s;
	const unsigned char *defn;

	s.name_length = NODE_LEN (hn);
	s.flags = hn->flags & NODE_POISONED;

	if (hn->type == NT_MACRO)
	  {
	    defn = cpp_macro_definition (pfile, hn);
	    s.definition_length = ustrlen (defn);
	  }
	else
	  {
	    defn = NODE_NAME (hn);
	    s.definition_length = s.name_length;
	  }
	
	if (fwrite (&s, sizeof (s), 1, f) != 1
	    || fwrite (defn, 1, s.definition_length, f) != s.definition_length)
	  {
	    cpp_errno (pfile, DL_ERROR, "while writing precompiled header");
	    return 0;
	  }
      }
      return 1;
      
    case NT_ASSERTION:
      /* Not currently implemented.  */
      return 1;

    default:
      abort ();
    }
}

/* This structure records the names of the defined macros.
   It's also used as a callback structure for size_initial_idents
   and save_idents.  */

struct cpp_savedstate
{
  /* A hash table of the defined identifiers.  */
  htab_t definedhash;
  /* The size of the definitions of those identifiers (the size of
     'definedstrs').  */
  size_t hashsize;
  /* APPLE LOCAL begin speed up pch validation */
  /* Number of definitions */
  size_t n_defs;
  /* Array of definitions.  In cpp_write_pch_deps it is used for sorting. */
  /* APPLE LOCAL end speed up pch validation */
  cpp_hashnode **defs;
  /* Space for the next definition.  Definitions are null-terminated
     strings.  */
  unsigned char *definedstrs;
};

/* Save this identifier into the state: put it in the hash table,
   put the definition in 'definedstrs'.  */

static int
save_idents (pfile, hn, ss_p)
     cpp_reader *pfile ATTRIBUTE_UNUSED;
     cpp_hashnode *hn;
     void *ss_p;
{
  struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
  
  if (hn->type != NT_VOID)
    {
      struct cpp_string news;
      void **slot;

      news.len = NODE_LEN (hn);
      news.text= NODE_NAME (hn);
      slot = htab_find_slot (ss->definedhash, &news, INSERT);
      if (*slot == NULL)
	{
	  struct cpp_string *sp;
	  unsigned char *text;
	  
	  sp = xmalloc (sizeof (struct cpp_string));
	  *slot = sp;

	  sp->len = NODE_LEN (hn);
	  sp->text = text = xmalloc (NODE_LEN (hn));
	  memcpy (text, NODE_NAME (hn), NODE_LEN (hn));
	}
    }

  return 1;
}

/* Hash some memory in a generic way.  */

static hashval_t
hashmem (p_p, sz)
     const void *p_p;
     size_t sz;
{
  const unsigned char *p = (const unsigned char *)p_p;
  size_t i;
  hashval_t h;
  
  h = 0;
  for (i = 0; i < sz; i++)
    h = h * 67 - (*p++ - 113);
  return h;
}

/* Hash a cpp string for the hashtable machinery.  */

static hashval_t
cpp_string_hash (a_p)
     const void *a_p;
{
  const struct cpp_string *a = (const struct cpp_string *) a_p;
  return hashmem (a->text, a->len);
}

/* Compare two cpp strings for the hashtable machinery.  */

static int
cpp_string_eq (a_p, b_p)
     const void *a_p;
     const void *b_p;
{
  const struct cpp_string *a = (const struct cpp_string *) a_p;
  const struct cpp_string *b = (const struct cpp_string *) b_p;
  return (a->len == b->len
	  && memcmp (a->text, b->text, a->len) == 0);
}

/* Save the current definitions of the cpp_reader for dependency
   checking purposes.  When writing a precompiled header, this should
   be called at the same point in the compilation as cpp_valid_state
   would be called when reading the precompiled header back in.  */

int
cpp_save_state (r, f)
     cpp_reader *r;
     FILE *f;
{
  /* Save the list of non-void identifiers for the dependency checking.  */
  r->savedstate = xmalloc (sizeof (struct cpp_savedstate));
  r->savedstate->definedhash = htab_create (100, cpp_string_hash, 
					    cpp_string_eq, NULL);
  cpp_forall_identifiers (r, save_idents, r->savedstate);
  
  /* Write out the list of defined identifiers.  */
  cpp_forall_identifiers (r, write_macdef, f);

  return 0;
}

/* Calculate the 'hashsize' field of the saved state.  */

static int
count_defs (pfile, hn, ss_p)
     cpp_reader *pfile ATTRIBUTE_UNUSED;
     cpp_hashnode *hn;
     void *ss_p;
{
  struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
  
  switch (hn->type)
    {
    case NT_MACRO:
      if (hn->flags & NODE_BUILTIN)
	return 1;
      
      /* else fall through.  */

    case NT_VOID:
      {
	struct cpp_string news;
	void **slot;
	
	/* APPLE LOCAL begin Symbol Separation */
	if (pfile->cinfo_state == CINFO_WRITE && pfile->cb.is_builtin_identifier)
	  if (pfile->cb.is_builtin_identifier (hn))
	    return 1;
	/* APPLE LOCAL end Symbol Separation */

	news.len = NODE_LEN (hn);
	news.text = NODE_NAME (hn);
	slot = htab_find (ss->definedhash, &news);
	if (slot == NULL)
	  /* APPLE LOCAL begin speedup pch validation */
	  {
	    ss->hashsize += NODE_LEN (hn) + 1;
	    ss->n_defs += 1;
	  }
	  /* APPLE LOCAL end speedup pch validation */
      }
      return 1;

    case NT_ASSERTION:
      /* Not currently implemented.  */
      return 1;

    default:
      abort ();
    }
}

/* APPLE LOCAL begin speed up pch validation */
/* Collect the identifiers into the state's string table. */
/* APPLE LOCAL end speed up pch validation */

static int
write_defs (pfile, hn, ss_p)
     cpp_reader *pfile ATTRIBUTE_UNUSED;
     cpp_hashnode *hn;
     void *ss_p;
{
  struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
  
  switch (hn->type)
    {
    case NT_MACRO:
      if (hn->flags & NODE_BUILTIN)
	return 1;
      
      /* else fall through.  */

    case NT_VOID:
      {
	struct cpp_string news;
	void **slot;
	
	/* APPLE LOCAL begin Symbol Separation */
	if (pfile->cinfo_state == CINFO_WRITE && pfile->cb.is_builtin_identifier)
	  if (pfile->cb.is_builtin_identifier (hn))
	    return 1;
	/* APPLE LOCAL end Symbol Separation */

	news.len = NODE_LEN (hn);
	news.text = NODE_NAME (hn);
	slot = htab_find (ss->definedhash, &news);
	if (slot == NULL)
	/* APPLE LOCAL begin speed up pch validation */
	  {
	    ss->defs[ss->n_defs] = hn;
	    ss->n_defs += 1;
	  }
	/* APPLE LOCAL end speed up pch validation */
      }
      return 1;

    case NT_ASSERTION:
      /* Not currently implemented.  */
      return 1;

    default:
      abort ();
    }
}

/* APPLE LOCAL begin speed up pch validation */
/* Comparison function for qsort.  The arguments point to pointers of
   type ht_hashnode *.  */
static int
comp_hashnodes (px, py)
     const void *px;
     const void *py;
{
  cpp_hashnode *x = *(cpp_hashnode **) px;
  cpp_hashnode *y = *(cpp_hashnode **) py;
  return ustrcmp (NODE_NAME (x), NODE_NAME (y));
}
/* APPLE LOCAL end speed up pch validation */

/* Write out the remainder of the dependency information.  This should be
   called after the PCH is ready to be saved.  */

int
cpp_write_pch_deps (r, f)
     cpp_reader *r;
     FILE *f;
{
  struct macrodef_struct z;
  struct cpp_savedstate *const ss = r->savedstate;
  unsigned char *definedstrs;
  /* APPLE LOCAL begin speed up pch validation */
  size_t i;
  
  /* Collect the list of identifiers which have been seen and
     weren't defined to anything previously.  */
  ss->hashsize = 0;
  ss->n_defs = 0;
  cpp_forall_identifiers (r, count_defs, ss);

  ss->defs = xmalloc (ss->n_defs * sizeof (cpp_hashnode *));
  ss->n_defs = 0;
  cpp_forall_identifiers (r, write_defs, ss);

  /* Sort the list, copy it into a buffer, and write it out. */
  qsort (ss->defs, ss->n_defs, sizeof (cpp_hashnode *), &comp_hashnodes);
  definedstrs = ss->definedstrs = xmalloc (ss->hashsize);
  for (i = 0; i < ss->n_defs; ++i)
    {
      size_t len = NODE_LEN (ss->defs[i]);
      memcpy (definedstrs, NODE_NAME (ss->defs[i]), len + 1);
      definedstrs += len + 1;
    }

  memset (&z, 0, sizeof (z));
  z.definition_length = ss->hashsize;
  if (fwrite (&z, sizeof (z), 1, f) != 1
      || fwrite (ss->definedstrs, ss->hashsize, 1, f) != 1)
    {
      cpp_errno (r, DL_ERROR, "while writing precompiled header");
      return -1;
    }
  free (ss->definedstrs);
  /* APPLE LOCAL end speed up pch validation */

  /* Free the saved state.  */
  free (ss);
  r->savedstate = NULL;
  return 0;
}

/* Write out the definitions of the preprocessor, in a form suitable for
   cpp_read_state.  */

int
cpp_write_pch_state (r, f)
     cpp_reader *r;
     FILE *f;
{
  struct macrodef_struct z;

  /* Write out the list of defined identifiers.  */
  cpp_forall_identifiers (r, write_macdef, f);
  memset (&z, 0, sizeof (z));
  if (fwrite (&z, sizeof (z), 1, f) != 1)
    {
      cpp_errno (r, DL_ERROR, "while writing precompiled header");
      return -1;
    }

  if (!r->deps)
    r->deps = deps_init ();

  if (deps_save (r->deps, f) != 0)
    {
      cpp_errno (r, DL_ERROR, "while writing precompiled header");
      return -1;
    }

/* APPLE LOCAL begin pch #import hack */
  if (_cpp_save_file_entries (r, f) != 0)
    {
      cpp_errno (r, DL_ERROR, "while writing precompiled header");
      return -1;
    }
/* APPLE LOCAL end pch #import hack */

  return 0;
}

/* APPLE LOCAL begin speed up pch validation */

/* Data structure to transform hash table nodes into a sorted array */

struct ht_node_list
{
  /* Array of nodes */
  cpp_hashnode **defs;
  /* Number of nodes in the array */
  size_t n_defs;
  /* Size of the allocated array */
  size_t asize;
};

/* Callback for collecting identifiers from hash table */

static int
collect_ht_nodes (pfile, hn, nl_p)
     cpp_reader *pfile ATTRIBUTE_UNUSED;
     cpp_hashnode *hn;
     void *nl_p;
{
  struct ht_node_list *const nl = (struct ht_node_list *)nl_p;

  if (hn->type != NT_VOID || hn->flags & NODE_POISONED)
    {
      if (nl->n_defs == nl->asize)
	{
	  nl->asize *= 2;
	  nl->defs = xrealloc (nl->defs, nl->asize * sizeof (cpp_hashnode *));
	}

      nl->defs[nl->n_defs] = hn;
      ++nl->n_defs;
    }
  return 1;
}

/* APPLE LOCAL end speed up pch validation */

/* Return nonzero if FD is a precompiled header which is consistent
   with the preprocessor's current definitions.  It will be consistent
   when:

   - anything that was defined just before the PCH was generated 
     is defined the same way now; and
   - anything that was not defined then, but is defined now, was not
     used by the PCH.

   NAME is used to print warnings if `warn_invalid_pch' or `warn_invalid_sr'
   is set in the reader's flags.
*/

int
cpp_valid_state (r, name, fd)
     cpp_reader *r;
     const char *name;
     int fd;
{
  struct macrodef_struct m;
  size_t namebufsz = 256;
  /* APPLE LOCAL pch dictcc mrs */
  unsigned char *namebuf;
  unsigned char *undeftab = NULL;
  /* APPLE LOCAL begin speed up pch validation */
  struct ht_node_list nl = { 0, 0, 0 };
  unsigned char *first, *last;
  /* APPLE LOCAL end speed up pch validation */
  unsigned int i;
  /* APPLE LOCAL begin pch dictcc mrs */
  int skip_validation;

  /* Skip pch validation if we have just validated it.  */
  skip_validation = CPP_OPTION (r, pch_preprocess)
    && CPP_OPTION (r, preprocessed);
  namebuf = xmalloc (namebufsz);
  /* APPLE LOCAL end pch dictcc mrs */

  /* Read in the list of identifiers that must be defined
     Check that they are defined in the same way.  */
  for (;;)
    {
      cpp_hashnode *h;
      const unsigned char *newdefn;
      
      if (read (fd, &m, sizeof (m)) != sizeof (m))
	goto error;
      
      if (m.name_length == 0)
	break;

      if (m.definition_length > namebufsz)
	{
	  free (namebuf);
	  namebufsz = m.definition_length + 256;
	  namebuf = xmalloc (namebufsz);
	}
      
      if ((size_t)read (fd, namebuf, m.definition_length) 
	  != m.definition_length)
	goto error;
      
      /* APPLE LOCAL begin pch dictcc mrs */
      if (skip_validation)
	continue;
      /* APPLE LOCAL end pch dictcc mrs */

      h = cpp_lookup (r, namebuf, m.name_length);
      if (m.flags & NODE_POISONED
	  || h->type != NT_MACRO
	  || h->flags & NODE_POISONED)
	{
	  /* APPLE LOCAL Symbol Separtion */
	  if (CPP_OPTION (r, warn_invalid_pch) || CPP_OPTION (r, warn_invalid_sr))
	    cpp_error (r, DL_WARNING,
		       "%s: not used because `%.*s' not defined",
		       name, m.name_length, namebuf);
	  goto fail;
	}

      newdefn = cpp_macro_definition (r, h);
      
      if (m.definition_length != ustrlen (newdefn)
	  || memcmp (namebuf, newdefn, m.definition_length) != 0)
	{
	  /* APPLE LOCAL Symbol Separtion */
	  if (CPP_OPTION (r, warn_invalid_pch) || CPP_OPTION (r, warn_invalid_sr))
	    cpp_error (r, DL_WARNING, 
	       "%s: not used because `%.*s' defined as `%s' not `%.*s'",
		       name, m.name_length, namebuf, newdefn + m.name_length,
		       m.definition_length - m.name_length,
		       namebuf +  m.name_length);
	  goto fail;
	}
    }
  free (namebuf);
  namebuf = NULL;

  /* Read in the list of identifiers that must not be defined.
     Check that they really aren't.  */
  undeftab = xmalloc (m.definition_length);
  if ((size_t) read (fd, undeftab, m.definition_length) != m.definition_length)
    goto error;

  /* APPLE LOCAL begin pch dictcc mrs */
  if (skip_validation)
    {
      free (undeftab);
      return 0;
    }
  /* APPLE LOCAL end pch dictcc mrs */

  /* APPLE LOCAL begin speed up pch validation */
  
  /* Collect identifiers from the current hash table.  */
  nl.n_defs = 0;
  nl.asize = 10;
  nl.defs = xmalloc (nl.asize * sizeof (cpp_hashnode *));
  cpp_forall_identifiers (r, &collect_ht_nodes, &nl);
  qsort (nl.defs, nl.n_defs, sizeof (cpp_hashnode *), &comp_hashnodes);

  /* Loop through nl.defs and undeftab, both of which are sorted lists.
     There should be no matches. */
  first = undeftab;
  last = undeftab + m.definition_length;
  i = 0;

  while (first < last && i < nl.n_defs)
    {
      int cmp = ustrcmp (first, NODE_NAME (nl.defs[i]));

      if (cmp < 0)
	first += ustrlen (first) + 1;
      else if (cmp > 0)
	++i;
      else
	{
	  /* APPLE LOCAL begin Symbol Separation */
	  if (CPP_OPTION (r, warn_invalid_pch) || CPP_OPTION (r, warn_invalid_sr))
	    cpp_error (r, DL_WARNING, "%s: not used because `%s' is defined",
		       name, first);
	  /* APPLE LOCAL end Symbol Separation */
	  goto fail;
	}
    }
  
  free(nl.defs);
  /* APPLE LOCAL end speed up pch validation */

  free (undeftab);

  /* We win!  */
  return 0;

 error:
  cpp_errno (r, DL_ERROR, "while reading precompiled header");
  return -1;

 fail:
  if (namebuf != NULL)
    free (namebuf);
  if (undeftab != NULL)
    free (undeftab);
  /* APPLE LOCAL begin speed up pch validation */
  if (nl.defs != NULL)
    free (nl.defs);
  /* APPLE LOCAL end speed up pch validation */
  return 1;
}

/* Save all the existing macros and assertions.  
   This code assumes that there might be hundreds, but not thousands of
   existing definitions.  */

struct save_macro_item {
  struct save_macro_item *next;
  struct cpp_hashnode macs[64];
};

struct save_macro_data 
{
  struct save_macro_item *macros;
  size_t count;
  char **saved_pragmas;
};

/* Save the definition of a single macro, so that it will persist across
   a PCH restore.  */

static int 
save_macros (r, h, data_p)
     cpp_reader *r ATTRIBUTE_UNUSED;
     cpp_hashnode *h;
     void *data_p;
{
  struct save_macro_data *data = (struct save_macro_data *)data_p;
  if (h->type != NT_VOID
      && (h->flags & NODE_BUILTIN) == 0)
    {
      cpp_hashnode *save;
      if (data->count == ARRAY_SIZE (data->macros->macs))
	{
	  struct save_macro_item *d = data->macros;
	  data->macros = xmalloc (sizeof (struct save_macro_item));
	  data->macros->next = d;
	  data->count = 0;
	}
      save = data->macros->macs + data->count;
      data->count++;
      memcpy (save, h, sizeof (struct cpp_hashnode));
      HT_STR (&save->ident) = xmemdup (HT_STR (HT_NODE (save)),
				       HT_LEN (HT_NODE (save)),
				       HT_LEN (HT_NODE (save)) + 1);
    }
  return 1;
}

/* Prepare to restore the state, by saving the currently-defined
   macros in 'data'.  */

void
cpp_prepare_state (r, data)
     cpp_reader *r;
     struct save_macro_data **data;
{
  struct save_macro_data *d = xmalloc (sizeof (struct save_macro_data));
  
  d->macros = NULL;
  d->count = ARRAY_SIZE (d->macros->macs);
  cpp_forall_identifiers (r, save_macros, d);
  d->saved_pragmas = _cpp_save_pragma_names (r);
  *data = d;
}

/* APPLE LOCAL begin speed up pch reading */
/* Removed definition of reset_ht */
/* APPLE LOCAL end speed up pch reading */


/* Given a precompiled header that was previously determined to be valid,
   apply all its definitions (and undefinitions) to the current state. 
   DEPNAME is passed to deps_restore.  */

int
cpp_read_state (r, name, f, data)
     cpp_reader *r;
     const char *name;
     FILE *f;
     struct save_macro_data *data;
{
  struct macrodef_struct m;
  size_t defnlen = 256;
  unsigned char *defn = xmalloc (defnlen);
  struct lexer_state old_state;
  struct save_macro_item *d;
  size_t i, mac_count;
  int saved_line = r->line;
  /* APPLE LOCAL pch distcc mrs */
  void (*saved_line_change)  PARAMS ((cpp_reader *, const cpp_token *, int));

  /* APPLE LOCAL pch distcc mrs */
  saved_line_change = r->cb.line_change;

  /* APPLE LOCAL begin speed up pch reading */
  /* Removed loop to erase hashtable entries. */
  /* APPLE LOCAL end speed up pch reading */

  /* Restore spec_nodes, which will be full of references to the old 
     hashtable entries and so will now be invalid.  */
  {
    struct spec_nodes *s = &r->spec_nodes;
    s->n_defined	= cpp_lookup (r, DSC("defined"));
    s->n_true		= cpp_lookup (r, DSC("true"));
    s->n_false		= cpp_lookup (r, DSC("false"));
    s->n__VA_ARGS__     = cpp_lookup (r, DSC("__VA_ARGS__"));
  }

  /* Run through the carefully-saved macros, insert them.  */
  d = data->macros;
  mac_count = data->count;
  while (d)
    {
      struct save_macro_item *nextd;
      for (i = 0; i < mac_count; i++)
	{
	  cpp_hashnode *h;
	  
	  h = cpp_lookup (r, HT_STR (HT_NODE (&d->macs[i])), 
			  HT_LEN (HT_NODE (&d->macs[i])));
	  h->type = d->macs[i].type;
	  h->flags = d->macs[i].flags;
	  h->value = d->macs[i].value;
	  free ((void *)HT_STR (HT_NODE (&d->macs[i])));
	}
      nextd = d->next;
      free (d);
      d = nextd;
      mac_count = ARRAY_SIZE (d->macs);
    }

  _cpp_restore_pragma_names (r, data->saved_pragmas);

  free (data);

  old_state = r->state;

  r->state.in_directive = 1;
  r->state.prevent_expansion = 1;
  r->state.angled_headers = 0;

  /* APPLE LOCAL pch distcc mrs */
  r->cb.line_change = 0;

  /* Read in the identifiers that must be defined.  */
  for (;;)
    {
      cpp_hashnode *h;
      
      if (fread (&m, sizeof (m), 1, f) != 1)
	goto error;
      
      if (m.name_length == 0)
	break;

      if (defnlen < m.definition_length + 1)
	{
	  defnlen = m.definition_length + 256;
	  defn = xrealloc (defn, defnlen);
	}

      if (fread (defn, 1, m.definition_length, f) != m.definition_length)
	goto error;
      defn[m.definition_length] = '\0';
      
      h = cpp_lookup (r, defn, m.name_length);

      if (h->type == NT_MACRO)
	_cpp_free_definition (h);
      if (m.flags & NODE_POISONED)
	h->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
      else if (m.name_length != m.definition_length)
	{
	  if (cpp_push_buffer (r, defn + m.name_length, 
			       m.definition_length - m.name_length, 
			       true, 1) != NULL)
	    {
	      /* We don't want a leading # to be interpreted as a
		 directive.  */
	      r->buffer->saved_flags = 0;
	      if (!_cpp_create_definition (r, h))
		abort ();
	      _cpp_pop_buffer (r);
	    }
	  else
	    abort ();
	}
    }

  r->state = old_state;
  r->line = saved_line;
  /* APPLE LOCAL pch distcc mrs */
  r->cb.line_change = saved_line_change;

  free (defn);
  defn = NULL;

  if (deps_restore (r->deps, f, CPP_OPTION (r, restore_pch_deps) ? name : NULL)
      != 0)
    goto error;

/* APPLE LOCAL begin pch #import hack */
  if (_cpp_read_file_entries (r, f) != 0)
    goto error;
/* APPLE LOCAL end pch #import hack */

  return 0;
  
 error:
  cpp_errno (r, DL_ERROR, "while reading precompiled header");
  return -1;
}