libFirm 1.20
libfirm/adt/obstack.h
00001 /* obstack.h - object stack macros
00002    Copyright (C) 1988-1994,1996-1999,2003,2004,2005
00003     Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.  */
00020 
00033 /* Summary:
00034 
00035 All the apparent functions defined here are macros. The idea
00036 is that you would use these pre-tested macros to solve a
00037 very specific set of problems, and they would run fast.
00038 Caution: no side-effects in arguments please!! They may be
00039 evaluated MANY times!!
00040 
00041 These macros operate a stack of objects.  Each object starts life
00042 small, and may grow to maturity.  (Consider building a word syllable
00043 by syllable.)  An object can move while it is growing.  Once it has
00044 been "finished" it never changes address again.  So the "top of the
00045 stack" is typically an immature growing object, while the rest of the
00046 stack is of mature, fixed size and fixed address objects.
00047 
00048 These routines grab large chunks of memory, using a function you
00049 supply, called `obstack_chunk_alloc'.  On occasion, they free chunks,
00050 by calling `obstack_chunk_free'.  You must define them and declare
00051 them before using any obstack macros.
00052 
00053 Each independent stack is represented by a `struct obstack'.
00054 Each of the obstack macros expects a pointer to such a structure
00055 as the first argument.
00056 
00057 One motivation for this package is the problem of growing char strings
00058 in symbol tables.  Unless you are "fascist pig with a read-only mind"
00059 --Gosper's immortal quote from HAKMEM item 154, out of context--you
00060 would not like to put any arbitrary upper limit on the length of your
00061 symbols.
00062 
00063 In practice this often means you will build many short symbols and a
00064 few long symbols.  At the time you are reading a symbol you don't know
00065 how long it is.  One traditional method is to read a symbol into a
00066 buffer, realloc()ating the buffer every time you try to read a symbol
00067 that is longer than the buffer.  This is beaut, but you still will
00068 want to copy the symbol from the buffer to a more permanent
00069 symbol-table entry say about half the time.
00070 
00071 With obstacks, you can work differently.  Use one obstack for all symbol
00072 names.  As you read a symbol, grow the name in the obstack gradually.
00073 When the name is complete, finalize it.  Then, if the symbol exists already,
00074 free the newly read name.
00075 
00076 The way we do this is to take a large chunk, allocating memory from
00077 low addresses.  When you want to build a symbol in the chunk you just
00078 add chars above the current "high water mark" in the chunk.  When you
00079 have finished adding chars, because you got to the end of the symbol,
00080 you know how long the chars are, and you can create a new object.
00081 Mostly the chars will not burst over the highest address of the chunk,
00082 because you would typically expect a chunk to be (say) 100 times as
00083 long as an average object.
00084 
00085 In case that isn't clear, when we have enough chars to make up
00086 the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
00087 so we just point to it where it lies.  No moving of chars is
00088 needed and this is the second win: potentially long strings need
00089 never be explicitly shuffled. Once an object is formed, it does not
00090 change its address during its lifetime.
00091 
00092 When the chars burst over a chunk boundary, we allocate a larger
00093 chunk, and then copy the partly formed object from the end of the old
00094 chunk to the beginning of the new larger chunk.  We then carry on
00095 accreting characters to the end of the object as we normally would.
00096 
00097 A special macro is provided to add a single char at a time to a
00098 growing object.  This allows the use of register variables, which
00099 break the ordinary 'growth' macro.
00100 
00101 Summary:
00102     We allocate large chunks.
00103     We carve out one object at a time from the current chunk.
00104     Once carved, an object never moves.
00105     We are free to append data of any size to the currently
00106       growing object.
00107     Exactly one object is growing in an obstack at any one time.
00108     You can run one obstack per control block.
00109     You may have as many control blocks as you dare.
00110     Because of the way we do it, you can `unwind' an obstack
00111       back to a previous state. (You may remove objects much
00112       as you would with a stack.)
00113 */
00114 
00115 
00116 /* Don't do the contents of this file more than once.  */
00117 
00118 #ifndef _OBSTACK_H
00119 #define _OBSTACK_H 1
00120 
00121 #include "../begin.h"
00122 
00125 /* We need the type of a pointer subtraction.  If __PTRDIFF_TYPE__ is
00126    defined, as with GNU C, use that; that way we don't pollute the
00127    namespace with <stddef.h>'s symbols.  Otherwise, include <stddef.h>
00128    and use ptrdiff_t.  */
00129 
00130 #ifdef __PTRDIFF_TYPE__
00131 # define PTR_INT_TYPE __PTRDIFF_TYPE__
00132 #else
00133 # include <stddef.h>
00134 # define PTR_INT_TYPE ptrdiff_t
00135 #endif
00136 
00137 /* If B is the base of an object addressed by P, return the result of
00138    aligning P to the next multiple of A + 1.  B and P must be of type
00139    char *.  A + 1 must be a power of 2.  */
00140 
00141 #define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
00142 
00143 /* Similiar to _BPTR_ALIGN (B, P, A), except optimize the common case
00144    where pointers can be converted to integers, aligned as integers,
00145    and converted back again.  If PTR_INT_TYPE is narrower than a
00146    pointer (e.g., the AS/400), play it safe and compute the alignment
00147    relative to B.  Otherwise, use the faster strategy of computing the
00148    alignment relative to 0.  */
00149 
00150 #define __PTR_ALIGN(B, P, A)                            \
00151   __BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \
00152         P, A)
00153 
00154 #include <string.h>
00155 #include <stdarg.h>
00156 
00157 struct _obstack_chunk       /* Lives at front of each chunk. */
00158 {
00159   char  *limit;         /* 1 past end of this chunk */
00160   struct _obstack_chunk *prev;  /* address of prior chunk or NULL */
00161   char  contents[4];        /* objects begin here */
00162 };
00163 
00164 struct obstack      /* control current object in current chunk */
00165 {
00166   PTR_INT_TYPE  chunk_size;     /* preferred size to allocate chunks in */
00167   struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */
00168   char  *object_base;       /* address of object we are building */
00169   char  *next_free;     /* where to add next char to current object */
00170   char  *chunk_limit;       /* address of char after current chunk */
00171   union
00172   {
00173     PTR_INT_TYPE tempint;
00174     void *tempptr;
00175   } temp;           /* Temporary for some macros.  */
00176   int   alignment_mask;     /* Mask of alignment for each object. */
00177   /* These prototypes vary based on `use_extra_arg', and we use
00178      casts to the prototypeless function type in all assignments,
00179      but having prototypes here quiets -Wstrict-prototypes.  */
00180   struct _obstack_chunk *(*chunkfun) (void *, PTR_INT_TYPE);
00181   void (*freefun) (void *, struct _obstack_chunk *);
00182   void *extra_arg;      /* first arg for chunk alloc/dealloc funcs */
00183   unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */
00184   unsigned maybe_empty_object:1;/* There is a possibility that the current
00185                    chunk contains a zero-length object.  This
00186                    prevents freeing the chunk if we allocate
00187                    a bigger chunk to replace it. */
00188   unsigned alloc_failed:1;  /* No longer used, as we now call the failed
00189                    handler on error, but retained for binary
00190                    compatibility.  */
00191 };
00192 
00193 /* Declare the external functions we use; they are in obstack.c.  */
00194 
00195 FIRM_API void _obstack_newchunk (struct obstack *, PTR_INT_TYPE);
00196 FIRM_API int _obstack_begin (struct obstack *, int, int,
00197                              void *(*) (PTR_INT_TYPE), void (*) (void *));
00198 FIRM_API int _obstack_begin_1 (struct obstack *, int, int,
00199                                void *(*) (void *, PTR_INT_TYPE),
00200                                void (*) (void *, void *), void *);
00201 FIRM_API PTR_INT_TYPE _obstack_memory_used (struct obstack *);
00202 
00203 FIRM_API void obstack_free (struct obstack *obstack, void *block);
00204 
00205 
00206 /* Error handler called when `obstack_chunk_alloc' failed to allocate
00207    more memory.  This can be set to a user defined function which
00208    should either abort gracefully or use longjump - but shouldn't
00209    return.  The default action is to print a message and abort.  */
00210 FIRM_API void (*obstack_alloc_failed_handler) (void);
00211 
00212 /* Exit value used when `print_and_abort' is used.  */
00213 FIRM_API int obstack_exit_failure;
00214 
00215 /* Pointer to beginning of object being allocated or to be allocated next.
00216    Note that this might not be the final address of the object
00217    because a new chunk might be needed to hold the final size.  */
00218 
00219 #define obstack_base(h) ((void *) (h)->object_base)
00220 
00221 /* Size for allocating ordinary chunks.  */
00222 
00223 #define obstack_chunk_size(h) ((h)->chunk_size)
00224 
00225 /* Pointer to next byte not yet allocated in current chunk.  */
00226 
00227 #define obstack_next_free(h)    ((h)->next_free)
00228 
00229 /* Mask specifying low bits that should be clear in address of an object.  */
00230 
00231 #define obstack_alignment_mask(h) ((h)->alignment_mask)
00232 
00233 /* To prevent prototype warnings provide complete argument list.  */
00234 #define obstack_init(h)                     \
00235   _obstack_begin ((h), 0, 0,                    \
00236           (void *(*) (PTR_INT_TYPE)) obstack_chunk_alloc,   \
00237           (void (*) (void *)) obstack_chunk_free)
00238 
00239 #define obstack_begin(h, size)                  \
00240   _obstack_begin ((h), (size), 0,               \
00241           (void *(*) (PTR_INT_TYPE)) obstack_chunk_alloc,   \
00242           (void (*) (void *)) obstack_chunk_free)
00243 
00244 #define obstack_specify_allocation(h, size, alignment, chunkfun, freefun)  \
00245   _obstack_begin ((h), (size), (alignment),                \
00246           (void *(*) (PTR_INT_TYPE)) (chunkfun),               \
00247           (void (*) (void *)) (freefun))
00248 
00249 #define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
00250   _obstack_begin_1 ((h), (size), (alignment),               \
00251             (void *(*) (void *, PTR_INT_TYPE)) (chunkfun),      \
00252             (void (*) (void *, void *)) (freefun), (arg))
00253 
00254 #define obstack_chunkfun(h, newchunkfun) \
00255   ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, PTR_INT_TYPE)) (newchunkfun))
00256 
00257 #define obstack_freefun(h, newfreefun) \
00258   ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
00259 
00260 #define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar))
00261 
00262 #define obstack_blank_fast(h,n) ((h)->next_free += (n))
00263 
00264 #define obstack_memory_used(h) _obstack_memory_used (h)
00265 
00266 #if defined __GNUC__ && defined __STDC__ && __STDC__
00267 /* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
00268    does not implement __extension__.  But that compiler doesn't define
00269    __GNUC_MINOR__.  */
00270 # if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
00271 #  define __extension__
00272 # endif
00273 
00274 /* For GNU C, if not -traditional,
00275    we can define these macros to compute all args only once
00276    without using a global variable.
00277    Also, we can avoid using the `temp' slot, to make faster code.  */
00278 
00279 # define obstack_object_size(OBSTACK)                   \
00280   __extension__                             \
00281   ({ struct obstack const *__o = (OBSTACK);             \
00282      (unsigned) (__o->next_free - __o->object_base); })
00283 
00284 # define obstack_room(OBSTACK)                      \
00285   __extension__                             \
00286   ({ struct obstack const *__o = (OBSTACK);             \
00287      (unsigned) (__o->chunk_limit - __o->next_free); })
00288 
00289 # define obstack_make_room(OBSTACK,length)              \
00290 __extension__                               \
00291 ({ struct obstack *__o = (OBSTACK);                 \
00292    int __len = (length);                        \
00293    if (__o->chunk_limit - __o->next_free < __len)           \
00294      _obstack_newchunk (__o, __len);                    \
00295    (void) 0; })
00296 
00297 # define obstack_empty_p(OBSTACK)                   \
00298   __extension__                             \
00299   ({ struct obstack const *__o = (OBSTACK);             \
00300      (__o->chunk->prev == 0                     \
00301       && __o->next_free == __PTR_ALIGN ((char *) __o->chunk,        \
00302                     __o->chunk->contents,       \
00303                     __o->alignment_mask)); })
00304 
00305 # define obstack_grow(OBSTACK,where,length)             \
00306 __extension__                               \
00307 ({ struct obstack *__o = (OBSTACK);                 \
00308    int __len = (length);                        \
00309    if (__o->next_free + __len > __o->chunk_limit)           \
00310      _obstack_newchunk (__o, __len);                    \
00311    memcpy (__o->next_free, where, __len);               \
00312    __o->next_free += __len;                     \
00313    (void) 0; })
00314 
00315 # define obstack_grow0(OBSTACK,where,length)                \
00316 __extension__                               \
00317 ({ struct obstack *__o = (OBSTACK);                 \
00318    int __len = (length);                        \
00319    if (__o->next_free + __len + 1 > __o->chunk_limit)           \
00320      _obstack_newchunk (__o, __len + 1);                \
00321    memcpy (__o->next_free, where, __len);               \
00322    __o->next_free += __len;                     \
00323    *(__o->next_free)++ = 0;                     \
00324    (void) 0; })
00325 
00326 # define obstack_1grow(OBSTACK,datum)                   \
00327 __extension__                               \
00328 ({ struct obstack *__o = (OBSTACK);                 \
00329    if (__o->next_free + 1 > __o->chunk_limit)               \
00330      _obstack_newchunk (__o, 1);                    \
00331    obstack_1grow_fast (__o, datum);                 \
00332    (void) 0; })
00333 
00334 /* These assume that the obstack alignment is good enough for pointers
00335    or ints, and that the data added so far to the current object
00336    shares that much alignment.  */
00337 
00338 # define obstack_ptr_grow(OBSTACK,datum)                \
00339 __extension__                               \
00340 ({ struct obstack *__o = (OBSTACK);                 \
00341    if (__o->next_free + sizeof (void *) > __o->chunk_limit)     \
00342      _obstack_newchunk (__o, sizeof (void *));              \
00343    obstack_ptr_grow_fast (__o, datum); })               \
00344 
00345 # define obstack_int_grow(OBSTACK,datum)                \
00346 __extension__                               \
00347 ({ struct obstack *__o = (OBSTACK);                 \
00348    if (__o->next_free + sizeof (int) > __o->chunk_limit)        \
00349      _obstack_newchunk (__o, sizeof (int));             \
00350    obstack_int_grow_fast (__o, datum); })
00351 
00352 # define obstack_ptr_grow_fast(OBSTACK,aptr)                \
00353 __extension__                               \
00354 ({ struct obstack *__o1 = (OBSTACK);                    \
00355    *(const void **) __o1->next_free = (aptr);               \
00356    __o1->next_free += sizeof (const void *);                \
00357    (void) 0; })
00358 
00359 # define obstack_int_grow_fast(OBSTACK,aint)                \
00360 __extension__                               \
00361 ({ struct obstack *__o1 = (OBSTACK);                    \
00362    *(int *) __o1->next_free = (aint);                   \
00363    __o1->next_free += sizeof (int);                 \
00364    (void) 0; })
00365 
00366 # define obstack_blank(OBSTACK,length)                  \
00367 __extension__                               \
00368 ({ struct obstack *__o = (OBSTACK);                 \
00369    int __len = (length);                        \
00370    if (__o->chunk_limit - __o->next_free < __len)           \
00371      _obstack_newchunk (__o, __len);                    \
00372    obstack_blank_fast (__o, __len);                 \
00373    (void) 0; })
00374 
00375 # define obstack_alloc(OBSTACK,length)                  \
00376 __extension__                               \
00377 ({ struct obstack *__h = (OBSTACK);                 \
00378    obstack_blank (__h, (length));                   \
00379    obstack_finish (__h); })
00380 
00381 # define obstack_copy(OBSTACK,where,length)             \
00382 __extension__                               \
00383 ({ struct obstack *__h = (OBSTACK);                 \
00384    obstack_grow (__h, (where), (length));               \
00385    obstack_finish (__h); })
00386 
00387 # define obstack_copy0(OBSTACK,where,length)                \
00388 __extension__                               \
00389 ({ struct obstack *__h = (OBSTACK);                 \
00390    obstack_grow0 (__h, (where), (length));              \
00391    obstack_finish (__h); })
00392 
00393 /* The local variable is named __o1 to avoid a name conflict
00394    when obstack_blank is called.  */
00395 # define obstack_finish(OBSTACK)                    \
00396 __extension__                               \
00397 ({ struct obstack *__o1 = (OBSTACK);                    \
00398    void *__value = (void *) __o1->object_base;              \
00399    if (__o1->next_free == __value)                  \
00400      __o1->maybe_empty_object = 1;                  \
00401    __o1->next_free                          \
00402      = __PTR_ALIGN (__o1->object_base, __o1->next_free,         \
00403             __o1->alignment_mask);              \
00404    if (__o1->next_free - (char *)__o1->chunk                \
00405        > __o1->chunk_limit - (char *)__o1->chunk)           \
00406      __o1->next_free = __o1->chunk_limit;               \
00407    __o1->object_base = __o1->next_free;                 \
00408    __value; })
00409 
00410 # define obstack_free(OBSTACK, OBJ)                 \
00411 __extension__                               \
00412 ({ struct obstack *__o = (OBSTACK);                 \
00413    void *__obj = (OBJ);                         \
00414    if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit)  \
00415      __o->next_free = __o->object_base = (char *)__obj;         \
00416    else (obstack_free) (__o, __obj); })
00417 
00418 #else /* not __GNUC__ or not __STDC__ */
00419 
00420 # define obstack_object_size(h) \
00421  (unsigned) ((h)->next_free - (h)->object_base)
00422 
00423 # define obstack_room(h)        \
00424  (unsigned) ((h)->chunk_limit - (h)->next_free)
00425 
00426 # define obstack_empty_p(h) \
00427  ((h)->chunk->prev == 0                         \
00428   && (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk,        \
00429                     (h)->chunk->contents,       \
00430                     (h)->alignment_mask))
00431 
00432 /* Note that the call to _obstack_newchunk is enclosed in (..., 0)
00433    so that we can avoid having void expressions
00434    in the arms of the conditional expression.
00435    Casting the third operand to void was tried before,
00436    but some compilers won't accept it.  */
00437 
00438 # define obstack_make_room(h,length)                    \
00439 ( (h)->temp.tempint = (length),                     \
00440   (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)      \
00441    ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0))
00442 
00443 # define obstack_grow(h,where,length)                   \
00444 ( (h)->temp.tempint = (length),                     \
00445   (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)      \
00446    ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),      \
00447   memcpy ((h)->next_free, where, (h)->temp.tempint),            \
00448   (h)->next_free += (h)->temp.tempint)
00449 
00450 # define obstack_grow0(h,where,length)                  \
00451 ( (h)->temp.tempint = (length),                     \
00452   (((h)->next_free + (h)->temp.tempint + 1 > (h)->chunk_limit)      \
00453    ? (_obstack_newchunk ((h), (h)->temp.tempint + 1), 0) : 0),      \
00454   memcpy ((h)->next_free, where, (h)->temp.tempint),            \
00455   (h)->next_free += (h)->temp.tempint,                  \
00456   *((h)->next_free)++ = 0)
00457 
00458 # define obstack_1grow(h,datum)                     \
00459 ( (((h)->next_free + 1 > (h)->chunk_limit)              \
00460    ? (_obstack_newchunk ((h), 1), 0) : 0),              \
00461   obstack_1grow_fast (h, datum))
00462 
00463 # define obstack_ptr_grow(h,datum)                  \
00464 ( (((h)->next_free + sizeof (char *) > (h)->chunk_limit)        \
00465    ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0),        \
00466   obstack_ptr_grow_fast (h, datum))
00467 
00468 # define obstack_int_grow(h,datum)                  \
00469 ( (((h)->next_free + sizeof (int) > (h)->chunk_limit)           \
00470    ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0),           \
00471   obstack_int_grow_fast (h, datum))
00472 
00473 # define obstack_ptr_grow_fast(h,aptr)                  \
00474   (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr))
00475 
00476 # define obstack_int_grow_fast(h,aint)                  \
00477   (((int *) ((h)->next_free += sizeof (int)))[-1] = (aint))
00478 
00479 # define obstack_blank(h,length)                    \
00480 ( (h)->temp.tempint = (length),                     \
00481   (((h)->chunk_limit - (h)->next_free < (h)->temp.tempint)      \
00482    ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),      \
00483   obstack_blank_fast (h, (h)->temp.tempint))
00484 
00485 # define obstack_alloc(h,length)                    \
00486  (obstack_blank ((h), (length)), obstack_finish ((h)))
00487 
00488 # define obstack_copy(h,where,length)                   \
00489  (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
00490 
00491 # define obstack_copy0(h,where,length)                  \
00492  (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
00493 
00494 # define obstack_finish(h)                      \
00495 ( ((h)->next_free == (h)->object_base                   \
00496    ? (((h)->maybe_empty_object = 1), 0)                 \
00497    : 0),                                \
00498   (h)->temp.tempptr = (h)->object_base,                 \
00499   (h)->next_free                            \
00500     = __PTR_ALIGN ((h)->object_base, (h)->next_free,            \
00501            (h)->alignment_mask),                \
00502   (((h)->next_free - (char *) (h)->chunk                \
00503     > (h)->chunk_limit - (char *) (h)->chunk)               \
00504    ? ((h)->next_free = (h)->chunk_limit) : 0),              \
00505   (h)->object_base = (h)->next_free,                    \
00506   (h)->temp.tempptr)
00507 
00508 # define obstack_free(h,obj)                        \
00509 ( (h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk,     \
00510   ((((h)->temp.tempint > 0                      \
00511     && (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk)) \
00512    ? (PTR_INT_TYPE) ((h)->next_free = (h)->object_base              \
00513         = (h)->temp.tempint + (char *) (h)->chunk)          \
00514    : (((obstack_free) ((h), (h)->temp.tempint + (char *) (h)->chunk), 0), 0)))
00515 
00516 #endif /* not __GNUC__ or not __STDC__ */
00517 
00522 #ifdef __cplusplus
00523 # define FIRM_NOTHROW throw ()
00524 #else
00525 # define FIRM_NOTHROW
00526 #endif
00527 
00533 #if defined(__GNUC__)
00534 # define FIRM_PRINTF(a,b) __attribute__((__format__(__printf__, a, b)))
00535 #else
00536 # define FIRM_PRINTF(a,b)
00537 #endif
00538 
00542 FIRM_API int obstack_printf(struct obstack *obst, const char *fmt, ...)
00543     FIRM_NOTHROW FIRM_PRINTF(2, 3);
00544 FIRM_API int obstack_vprintf(struct obstack *obst, const char *fmt, va_list ap)
00545     FIRM_NOTHROW FIRM_PRINTF(2, 0);
00546 
00549 #include "../end.h"
00550 
00551 #endif