133965Sjdp/*
233965Sjdp * Copyright (c) 1990 Regents of the University of California.
333965Sjdp * All rights reserved.
433965Sjdp *
533965Sjdp * %sccs.include.redist.c%
633965Sjdp */
733965Sjdp
889857Sobrien
989857Sobrien/*
1089857Sobrien
1189857Sobrien@deftypefun int xatexit (void (*@var{fn}) (void))
1289857Sobrien
1389857SobrienBehaves as the standard @code{atexit} function, but with no limit on
1489857Sobrienthe number of registered functions.  Returns 0 on success, or @minus{}1 on
1589857Sobrienfailure.  If you use @code{xatexit} to register functions, you must use
1689857Sobrien@code{xexit} to terminate your program.
1789857Sobrien
1889857Sobrien@end deftypefun
1989857Sobrien
2089857Sobrien*/
2189857Sobrien
2233965Sjdp/* Adapted from newlib/libc/stdlib/{,at}exit.[ch].
2333965Sjdp   If you use xatexit, you must call xexit instead of exit.  */
2433965Sjdp
25218822Sdim#ifdef HAVE_CONFIG_H
26218822Sdim#include "config.h"
27218822Sdim#endif
2833965Sjdp#include "ansidecl.h"
2933965Sjdp#include "libiberty.h"
3033965Sjdp
3133965Sjdp#include <stdio.h>
3233965Sjdp
3333965Sjdp#include <stddef.h>
3433965Sjdp
35104834Sobrien#if VMS
36104834Sobrien#include <stdlib.h>
37104834Sobrien#include <unixlib.h>
38104834Sobrien#else
3933965Sjdp/* For systems with larger pointers than ints, this must be declared.  */
40218822SdimPTR malloc (size_t);
41104834Sobrien#endif
4233965Sjdp
43218822Sdimstatic void xatexit_cleanup (void);
4433965Sjdp
4533965Sjdp/* Pointer to function run by xexit.  */
46218822Sdimextern void (*_xexit_cleanup) (void);
4733965Sjdp
4833965Sjdp#define	XATEXIT_SIZE 32
4933965Sjdp
5033965Sjdpstruct xatexit {
5133965Sjdp	struct	xatexit *next;		/* next in list */
5233965Sjdp	int	ind;			/* next index in this table */
53218822Sdim	void	(*fns[XATEXIT_SIZE]) (void);	/* the table itself */
5433965Sjdp};
5533965Sjdp
5633965Sjdp/* Allocate one struct statically to guarantee that we can register
5733965Sjdp   at least a few handlers.  */
5833965Sjdpstatic struct xatexit xatexit_first;
5933965Sjdp
6033965Sjdp/* Points to head of LIFO stack.  */
6133965Sjdpstatic struct xatexit *xatexit_head = &xatexit_first;
6233965Sjdp
6333965Sjdp/* Register function FN to be run by xexit.
6433965Sjdp   Return 0 if successful, -1 if not.  */
6533965Sjdp
6633965Sjdpint
67218822Sdimxatexit (void (*fn) (void))
6833965Sjdp{
6933965Sjdp  register struct xatexit *p;
7033965Sjdp
7133965Sjdp  /* Tell xexit to call xatexit_cleanup.  */
7233965Sjdp  if (!_xexit_cleanup)
7333965Sjdp    _xexit_cleanup = xatexit_cleanup;
7433965Sjdp
7533965Sjdp  p = xatexit_head;
7633965Sjdp  if (p->ind >= XATEXIT_SIZE)
7733965Sjdp    {
7833965Sjdp      if ((p = (struct xatexit *) malloc (sizeof *p)) == NULL)
7933965Sjdp	return -1;
8033965Sjdp      p->ind = 0;
8133965Sjdp      p->next = xatexit_head;
8233965Sjdp      xatexit_head = p;
8333965Sjdp    }
8433965Sjdp  p->fns[p->ind++] = fn;
8533965Sjdp  return 0;
8633965Sjdp}
8733965Sjdp
8833965Sjdp/* Call any cleanup functions.  */
8933965Sjdp
9033965Sjdpstatic void
91218822Sdimxatexit_cleanup (void)
9233965Sjdp{
9333965Sjdp  register struct xatexit *p;
9433965Sjdp  register int n;
9533965Sjdp
9633965Sjdp  for (p = xatexit_head; p; p = p->next)
9733965Sjdp    for (n = p->ind; --n >= 0;)
9833965Sjdp      (*p->fns[n]) ();
9933965Sjdp}
100