/* Part of CPP library. (Precompiled header reading/writing.) Copyright (C) 2000-2026 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 3, or (at your option) anylater version. This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details. You should have received a copy of the GNU General Public Licensealong with this program; see the file COPYING3. If not see<http://www.gnu.org/licenses/>. */ #include "config.h"#include "system.h"#include "cpplib.h"#include "internal.h"#include "hashtab.h"#include "mkdeps.h" static int write_macdef (cpp_reader *, cpp_hashnode *, void *);static int save_idents (cpp_reader *, cpp_hashnode *, void *);static hashval_t hashmem (const void *, size_t);static hashval_t cpp_string_hash (const void *);static int cpp_string_eq (const void *, const void *);static int count_defs (cpp_reader *, cpp_hashnode *, void *);static int comp_hashnodes (const void *, const void *);static int collect_ht_nodes (cpp_reader *, cpp_hashnode *, void *);static int write_defs (cpp_reader *, cpp_hashnode *, void *);static int save_macros (cpp_reader *, cpp_hashnode *, void *);static int _cpp_save_pushed_macros (cpp_reader *, FILE *);static int _cpp_restore_pushed_macros (cpp_reader *, FILE *); /* 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 intwrite_macdef (cpp_reader *pfile, cpp_hashnode *hn, void *file_p){ FILE *f = (FILE *) file_p; bool is_void = false; switch (hn->type) { case NT_VOID: if (! (hn->flags & NODE_POISONED)) return 1; is_void = true; goto poisoned; case NT_BUILTIN_MACRO: return 1; case NT_USER_MACRO: if (hn->value.macro->kind != cmk_assert) { poisoned: struct macrodef_struct s; const unsigned char *defn; s.name_length = NODE_LEN (hn); s.flags = hn->flags & NODE_POISONED; if (is_void) { defn = NODE_NAME (hn); s.definition_length = s.name_length; } else { defn = cpp_macro_definition (pfile, hn); s.definition_length = ustrlen (defn); } if (fwrite (&s, sizeof (s), 1, f) != 1 || fwrite (defn, 1, s.definition_length, f) != s.definition_length) { cpp_errno (pfile, CPP_DL_ERROR, "while writing precompiled header"); return 0; } } 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; /* Number of definitions */ size_t n_defs; /* Array of definitions. In cpp_write_pch_deps it is used for sorting. */ 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 intsave_idents (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 = XNEW (struct cpp_string); *slot = sp; sp->len = NODE_LEN (hn); sp->text = text = XNEWVEC (unsigned char, NODE_LEN (hn)); memcpy (text, NODE_NAME (hn), NODE_LEN (hn)); } } return 1;} /* Hash some memory in a generic way. */ static hashval_thashmem (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_tcpp_string_hash (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 intcpp_string_eq (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);} /* Free memory associated with cpp_string. */ static voidcpp_string_free (void *a_p){ struct cpp_string *a = (struct cpp_string *) a_p; free ((void *) a->text); free (a);} /* 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. */ intcpp_save_state (cpp_reader *r, FILE *f){ /* Save the list of non-void identifiers for the dependency checking. */ r->savedstate = XNEW (struct cpp_savedstate); r->savedstate->definedhash = htab_create (100, cpp_string_hash, cpp_string_eq, cpp_string_free); 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 intcount_defs (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_BUILTIN_MACRO: return 1; case NT_USER_MACRO: if (hn->value.macro->kind == cmk_assert) return 1; /* fall through. */ case NT_VOID: { struct cpp_string news; void **slot; news.len = NODE_LEN (hn); news.text = NODE_NAME (hn); slot = (void **) htab_find (ss->definedhash, &news); if (slot == NULL) { ss->hashsize += NODE_LEN (hn) + 1; ss->n_defs += 1; } } return 1; default: abort (); }} /* Collect the identifiers into the state's string table. */static intwrite_defs (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_BUILTIN_MACRO: return 1; case NT_USER_MACRO: if (hn->value.macro->kind == cmk_assert) return 1; /* fall through. */ case NT_VOID: { struct cpp_string news; void **slot; news.len = NODE_LEN (hn); news.text = NODE_NAME (hn); slot = (void **) htab_find (ss->definedhash, &news); if (slot == NULL) { ss->defs[ss->n_defs] = hn; ss->n_defs += 1; } } return 1; default: abort (); }} /* Comparison function for qsort. The arguments point to pointers of type ht_hashnode *. */static intcomp_hashnodes (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));} /* Write out the remainder of the dependency information. This should be called after the PCH is ready to be saved. */ intcpp_write_pch_deps (cpp_reader *r, FILE *f){ struct macrodef_struct z; struct cpp_savedstate *const ss = r->savedstate; unsigned char *definedstrs; 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 = XNEWVEC (cpp_hashnode *, ss->n_defs); 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 = XNEWVEC (unsigned char, 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, CPP_DL_ERROR, "while writing precompiled header"); return -1; } free (ss->definedstrs); free (ss->defs); htab_delete (ss->definedhash); /* Free the saved state. */ free (ss); r->savedstate = NULL; /* Save the next value of __COUNTER__. */ if (fwrite (&r->counter, sizeof (r->counter), 1, f) != 1) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } return 0;} /* Write out the definitions of the preprocessor, in a form suitable for cpp_read_state. */ intcpp_write_pch_state (cpp_reader *r, FILE *f){ if (!r->deps) r->deps = deps_init (); if (deps_save (r->deps, f) != 0) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } if (! _cpp_save_file_entries (r, f)) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } /* Save the next __COUNTER__ value. When we include a precompiled header, we need to start at the offset we would have if the header had been included normally. */ if (fwrite (&r->counter, sizeof (r->counter), 1, f) != 1) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } /* Write saved macros. */ if (! _cpp_save_pushed_macros (r, f)) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } return 0;} static int_cpp_restore_pushed_macros (cpp_reader *r, FILE *f){ size_t count_saved = 0; size_t i; struct def_pragma_macro *p; size_t nlen; uchar *defn; size_t defnlen; if (fread (&count_saved, sizeof (count_saved), 1, f) != 1) return 0; if (! count_saved) return 1; for (i = 0; i < count_saved; i++) { if (fread (&nlen, sizeof (nlen), 1, f) != 1) return 0; p = XNEW (struct def_pragma_macro); memset (p, 0, sizeof (struct def_pragma_macro)); p->name = XNEWVAR (char, nlen + 1); p->name[nlen] = 0; if (fread (p->name, nlen, 1, f) != 1) return 0; if (fread (&defnlen, sizeof (defnlen), 1, f) != 1) return 0; if (defnlen == 0) p->is_undef = 1; else { defn = XNEWVEC (uchar, defnlen + 1); defn[defnlen] = 0; if (fread (defn, defnlen, 1, f) != 1) return 0; p->definition = defn; if (fread (&(p->line), sizeof (location_t), 1, f) != 1) return 0; defnlen = 0; if (fread (&defnlen, sizeof (defnlen), 1, f) != 1) return 0; p->syshdr = ((defnlen & 1) != 0 ? 1 : 0); p->used = ((defnlen & 2) != 0 ? 1 : 0); } p->next = r->pushed_macros; r->pushed_macros = p; } return 1;} static int_cpp_save_pushed_macros (cpp_reader *r, FILE *f){ size_t count_saved = 0; size_t i; struct def_pragma_macro *p,**pp; size_t defnlen; /* Get count. */ p = r->pushed_macros; while (p != NULL) { count_saved++; p = p->next; } if (fwrite (&count_saved, sizeof (count_saved), 1, f) != 1) return 0; if (!count_saved) return 1; pp = (struct def_pragma_macro **) alloca (sizeof (struct def_pragma_macro *) * count_saved); /* Store them in reverse order. */ p = r->pushed_macros; i = count_saved; while (p != NULL) { --i; pp[i] = p; p = p->next; } for (i = 0; i < count_saved; i++) { defnlen = strlen (pp[i]->name); if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1 || fwrite (pp[i]->name, defnlen, 1, f) != 1) return 0; if (pp[i]->is_undef) { defnlen = 0; if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1) return 0; } else { defnlen = ustrlen (pp[i]->definition);Lines 1–500 of 970. Load more
/* Part of CPP library. (Precompiled header reading/writing.) Copyright (C) 2000-2026 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 3, 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; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" #include "system.h" #include "cpplib.h" #include "internal.h" #include "hashtab.h" #include "mkdeps.h" static int write_macdef (cpp_reader *, cpp_hashnode *, void *); static int save_idents (cpp_reader *, cpp_hashnode *, void *); static hashval_t hashmem (const void *, size_t); static hashval_t cpp_string_hash (const void *); static int cpp_string_eq (const void *, const void *); static int count_defs (cpp_reader *, cpp_hashnode *, void *); static int comp_hashnodes (const void *, const void *); static int collect_ht_nodes (cpp_reader *, cpp_hashnode *, void *); static int write_defs (cpp_reader *, cpp_hashnode *, void *); static int save_macros (cpp_reader *, cpp_hashnode *, void *); static int _cpp_save_pushed_macros (cpp_reader *, FILE *); static int _cpp_restore_pushed_macros (cpp_reader *, FILE *); /* 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 (cpp_reader *pfile, cpp_hashnode *hn, void *file_p) { FILE *f = (FILE *) file_p; bool is_void = false; switch (hn->type) { case NT_VOID: if (! (hn->flags & NODE_POISONED)) return 1; is_void = true; goto poisoned; case NT_BUILTIN_MACRO: return 1; case NT_USER_MACRO: if (hn->value.macro->kind != cmk_assert) { poisoned: struct macrodef_struct s; const unsigned char *defn; s.name_length = NODE_LEN (hn); s.flags = hn->flags & NODE_POISONED; if (is_void) { defn = NODE_NAME (hn); s.definition_length = s.name_length; } else { defn = cpp_macro_definition (pfile, hn); s.definition_length = ustrlen (defn); } if (fwrite (&s, sizeof (s), 1, f) != 1 || fwrite (defn, 1, s.definition_length, f) != s.definition_length) { cpp_errno (pfile, CPP_DL_ERROR, "while writing precompiled header"); return 0; } } 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; /* Number of definitions */ size_t n_defs; /* Array of definitions. In cpp_write_pch_deps it is used for sorting. */ 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 (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 = XNEW (struct cpp_string); *slot = sp; sp->len = NODE_LEN (hn); sp->text = text = XNEWVEC (unsigned char, NODE_LEN (hn)); memcpy (text, NODE_NAME (hn), NODE_LEN (hn)); } } return 1; } /* Hash some memory in a generic way. */ static hashval_t hashmem (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 (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 (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); } /* Free memory associated with cpp_string. */ static void cpp_string_free (void *a_p) { struct cpp_string *a = (struct cpp_string *) a_p; free ((void *) a->text); free (a); } /* 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 (cpp_reader *r, FILE *f) { /* Save the list of non-void identifiers for the dependency checking. */ r->savedstate = XNEW (struct cpp_savedstate); r->savedstate->definedhash = htab_create (100, cpp_string_hash, cpp_string_eq, cpp_string_free); 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 (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_BUILTIN_MACRO: return 1; case NT_USER_MACRO: if (hn->value.macro->kind == cmk_assert) return 1; /* fall through. */ case NT_VOID: { struct cpp_string news; void **slot; news.len = NODE_LEN (hn); news.text = NODE_NAME (hn); slot = (void **) htab_find (ss->definedhash, &news); if (slot == NULL) { ss->hashsize += NODE_LEN (hn) + 1; ss->n_defs += 1; } } return 1; default: abort (); } } /* Collect the identifiers into the state's string table. */ static int write_defs (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_BUILTIN_MACRO: return 1; case NT_USER_MACRO: if (hn->value.macro->kind == cmk_assert) return 1; /* fall through. */ case NT_VOID: { struct cpp_string news; void **slot; news.len = NODE_LEN (hn); news.text = NODE_NAME (hn); slot = (void **) htab_find (ss->definedhash, &news); if (slot == NULL) { ss->defs[ss->n_defs] = hn; ss->n_defs += 1; } } return 1; default: abort (); } } /* Comparison function for qsort. The arguments point to pointers of type ht_hashnode *. */ static int comp_hashnodes (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)); } /* 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 (cpp_reader *r, FILE *f) { struct macrodef_struct z; struct cpp_savedstate *const ss = r->savedstate; unsigned char *definedstrs; 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 = XNEWVEC (cpp_hashnode *, ss->n_defs); 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 = XNEWVEC (unsigned char, 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, CPP_DL_ERROR, "while writing precompiled header"); return -1; } free (ss->definedstrs); free (ss->defs); htab_delete (ss->definedhash); /* Free the saved state. */ free (ss); r->savedstate = NULL; /* Save the next value of __COUNTER__. */ if (fwrite (&r->counter, sizeof (r->counter), 1, f) != 1) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } return 0; } /* Write out the definitions of the preprocessor, in a form suitable for cpp_read_state. */ int cpp_write_pch_state (cpp_reader *r, FILE *f) { if (!r->deps) r->deps = deps_init (); if (deps_save (r->deps, f) != 0) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } if (! _cpp_save_file_entries (r, f)) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } /* Save the next __COUNTER__ value. When we include a precompiled header, we need to start at the offset we would have if the header had been included normally. */ if (fwrite (&r->counter, sizeof (r->counter), 1, f) != 1) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } /* Write saved macros. */ if (! _cpp_save_pushed_macros (r, f)) { cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header"); return -1; } return 0; } static int _cpp_restore_pushed_macros (cpp_reader *r, FILE *f) { size_t count_saved = 0; size_t i; struct def_pragma_macro *p; size_t nlen; uchar *defn; size_t defnlen; if (fread (&count_saved, sizeof (count_saved), 1, f) != 1) return 0; if (! count_saved) return 1; for (i = 0; i < count_saved; i++) { if (fread (&nlen, sizeof (nlen), 1, f) != 1) return 0; p = XNEW (struct def_pragma_macro); memset (p, 0, sizeof (struct def_pragma_macro)); p->name = XNEWVAR (char, nlen + 1); p->name[nlen] = 0; if (fread (p->name, nlen, 1, f) != 1) return 0; if (fread (&defnlen, sizeof (defnlen), 1, f) != 1) return 0; if (defnlen == 0) p->is_undef = 1; else { defn = XNEWVEC (uchar, defnlen + 1); defn[defnlen] = 0; if (fread (defn, defnlen, 1, f) != 1) return 0; p->definition = defn; if (fread (&(p->line), sizeof (location_t), 1, f) != 1) return 0; defnlen = 0; if (fread (&defnlen, sizeof (defnlen), 1, f) != 1) return 0; p->syshdr = ((defnlen & 1) != 0 ? 1 : 0); p->used = ((defnlen & 2) != 0 ? 1 : 0); } p->next = r->pushed_macros; r->pushed_macros = p; } return 1; } static int _cpp_save_pushed_macros (cpp_reader *r, FILE *f) { size_t count_saved = 0; size_t i; struct def_pragma_macro *p,**pp; size_t defnlen; /* Get count. */ p = r->pushed_macros; while (p != NULL) { count_saved++; p = p->next; } if (fwrite (&count_saved, sizeof (count_saved), 1, f) != 1) return 0; if (!count_saved) return 1; pp = (struct def_pragma_macro **) alloca (sizeof (struct def_pragma_macro *) * count_saved); /* Store them in reverse order. */ p = r->pushed_macros; i = count_saved; while (p != NULL) { --i; pp[i] = p; p = p->next; } for (i = 0; i < count_saved; i++) { defnlen = strlen (pp[i]->name); if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1 || fwrite (pp[i]->name, defnlen, 1, f) != 1) return 0; if (pp[i]->is_undef) { defnlen = 0; if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1) return 0; } else { defnlen = ustrlen (pp[i]->definition);