1 /* Copyright (C) 1999 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gsnotify.c,v 1.2.6.1.2.1 2003/01/17 00:49:03 giles Exp $ */
20 /* Notification machinery implementation */
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsstruct.h"
24 #include "gsnotify.h"
25 
26 /* GC descriptors */
27 private_st_gs_notify_registration();
28 public_st_gs_notify_list();
29 
30 /* Initialize a notification list. */
31 void
gs_notify_init(gs_notify_list_t * nlist,gs_memory_t * mem)32 gs_notify_init(gs_notify_list_t *nlist, gs_memory_t *mem)
33 {
34     nlist->first = 0;
35     nlist->memory = mem;
36 }
37 
38 /* Register a client. */
39 int
gs_notify_register(gs_notify_list_t * nlist,gs_notify_proc_t proc,void * proc_data)40 gs_notify_register(gs_notify_list_t *nlist, gs_notify_proc_t proc,
41 		   void *proc_data)
42 {
43     gs_notify_registration_t *nreg =
44 	gs_alloc_struct(nlist->memory, gs_notify_registration_t,
45 			&st_gs_notify_registration, "gs_notify_register");
46 
47     if (nreg == 0)
48 	return_error(gs_error_VMerror);
49     nreg->proc = proc;
50     nreg->proc_data = proc_data;
51     nreg->next = nlist->first;
52     nlist->first = nreg;
53     return 0;
54 }
55 
56 /*
57  * Unregister a client.  Return 1 if the client was registered, 0 if not.
58  * If proc_data is 0, unregister all registrations of that proc; otherwise,
59  * unregister only the registration of that procedure with that proc_data.
60  */
61 private void
no_unreg_proc(void * pdata)62 no_unreg_proc(void *pdata)
63 {
64 }
65 int
gs_notify_unregister_calling(gs_notify_list_t * nlist,gs_notify_proc_t proc,void * proc_data,void (* unreg_proc)(P1 (void * pdata)))66 gs_notify_unregister_calling(gs_notify_list_t *nlist, gs_notify_proc_t proc,
67 			     void *proc_data,
68 			     void (*unreg_proc)(P1(void *pdata)))
69 {
70     gs_notify_registration_t **prev = &nlist->first;
71     gs_notify_registration_t *cur;
72     bool found = 0;
73 
74     while ((cur = *prev) != 0)
75 	if (cur->proc == proc &&
76 	    (proc_data == 0 || cur->proc_data == proc_data)
77 	    ) {
78 	    *prev = cur->next;
79 	    unreg_proc(cur->proc_data);
80 	    gs_free_object(nlist->memory, cur, "gs_notify_unregister");
81 	    found = 1;
82 	} else
83 	    prev = &cur->next;
84     return found;
85 }
86 int
gs_notify_unregister(gs_notify_list_t * nlist,gs_notify_proc_t proc,void * proc_data)87 gs_notify_unregister(gs_notify_list_t *nlist, gs_notify_proc_t proc,
88 		     void *proc_data)
89 {
90     return gs_notify_unregister_calling(nlist, proc, proc_data, no_unreg_proc);
91 }
92 
93 /*
94  * Notify the clients on a list.  If an error occurs, return the first
95  * error code, but notify all clients regardless.
96  */
97 int
gs_notify_all(gs_notify_list_t * nlist,void * event_data)98 gs_notify_all(gs_notify_list_t *nlist, void *event_data)
99 {
100     gs_notify_registration_t *cur;
101     gs_notify_registration_t *next;
102     int ecode = 0;
103 
104     for (next = nlist->first; (cur = next) != 0;) {
105 	int code;
106 
107 	next = cur->next;
108 	code = cur->proc(cur->proc_data, event_data);
109 	if (code < 0 && ecode == 0)
110 	    ecode = code;
111     }
112     return ecode;
113 }
114 
115 /* Release a notification list. */
116 void
gs_notify_release(gs_notify_list_t * nlist)117 gs_notify_release(gs_notify_list_t *nlist)
118 {
119     gs_memory_t *mem = nlist->memory;
120 
121     while (nlist->first) {
122 	gs_notify_registration_t *next = nlist->first->next;
123 
124 	gs_free_object(mem, nlist->first, "gs_notify_release");
125 	nlist->first = next;
126     }
127 }
128