]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/plus.c
set the initial node refcount to one so they don't get gc'd before the ares callback...
[1ts-debian.git] / zephyr / zwgc / plus.c
1 /* 
2   This file contains code related to the zwgcplus extension to zwgc.
3   zwgc is copyrighted by the Massachusetts Institute of Technology.
4   This file is public domain.
5   Written by Andrew Plotkin, ap1i+@andrew.cmu.edu
6   Timequeue code added by Ryan Ingram, ryani+@andrew.cmu.edu
7   Rewritten for incorporation into MIT zwgc from 2.0.2 by Derrick Brashear
8  */
9
10 #include <sysdep.h>
11 #ifdef CMU_ZWGCPLUS
12 #if (!defined(lint) && !defined(SABER))
13 static char rcsid_plus_c[] = "$Id: plus.c,v 1.7 1998/08/10 22:54:11 shadow Exp $";
14 #endif
15
16 #include <zephyr/mit-copyright.h>
17 #include <zephyr/zephyr.h>
18
19 #include "new_memory.h"
20 #include "node.h"
21 #include "exec.h"
22 #include "eval.h"
23 #include "node.h"
24 #include "buffer.h"
25 #include "port.h"
26 #include "variables.h"
27 #include "notice.h"
28 #include "X_gram.h"
29 #include "xrevstack.h"
30 #include "plus.h"
31
32 int get_full_names = 0;
33
34 #define HASHSIZE (251)
35
36 typedef struct timenode_s {
37   ZNotice_t *notice;
38   struct timenode_s *next;
39   time_t when;
40   char *event_name;
41 } TimeNode;
42
43 typedef struct _notnode {
44     ZNotice_t *notice;
45     int fake_notice; /* if TRUE, do not call ZFreeNotice() */
46     int refcount;
47     struct _notnode *next;
48     char *opcode;
49     char *hname;
50 } notnode;
51
52 static ZNotice_t *stored_notice;
53 static notnode *notlist[HASHSIZE];
54 TimeNode *timeq_head = NULL;
55
56 TimeNode 
57 *addtimenode(head, node)
58   TimeNode *head;
59   TimeNode *node;
60 {
61   if(head == NULL) {
62 #ifdef DEBUG_TIMEQUEUE
63     fprintf(stderr, "adding new timenode; creating queue\n");
64 #endif
65     node->next = NULL;
66     return node;
67   }
68   
69   if(head->when > node->when) {
70 #ifdef DEBUG_TIMEQUEUE
71     fprintf(stderr, "adding new timenode at start of queue\n");
72 #endif
73     node->next = head;
74     return node;
75   }
76
77   head->next = addtimenode(head->next, node);
78   return head;
79 }
80
81 void 
82 handle_timeq_event(event)
83   TimeNode *event;
84 {
85   char *tmp;
86
87   char buf[128];
88   notnode *pt;
89   int bx = list_hash_fun(event->notice);
90
91   for (pt=notlist[bx]; pt && pt->notice!=event->notice; pt=pt->next);
92
93   /* "time-" + event_name + '\0' */
94 #ifdef DEBUG_TIMEQUEUE
95   fprintf(stderr, "handle_timeq_event()\n");
96 #endif
97
98   if (strlen(event->event_name)<123)
99     sprintf(buf, "time-%s", event->event_name);
100   else
101     sprintf(buf, "time-bogus");
102
103 #ifdef DEBUG_TIMEQUEUE
104   fprintf(stderr, "opcode: %s\n", buf);
105 #endif
106
107   event->notice->z_version = "zwgcplus-repeat";
108   event->notice->z_opcode = buf;
109  
110   reprocess_notice(event->notice, pt->hname);
111
112 #ifdef DEBUG_TIMEQUEUE
113   fprintf(stderr, "end handle_timeq_event()\n");
114 #endif
115 }
116
117 void 
118 schedule_event(secs, name, notice)
119   long secs;
120   char *name;
121   ZNotice_t *notice;
122 {
123   time_t eventtime = (time(NULL)) + secs;
124   TimeNode *newnode;
125   char *buf;
126
127 #ifdef DEBUG_TIMEQUEUE
128   fprintf(stderr, "schedule_event(%ld, %ld, %s)\n", eventtime, secs, name);
129 #endif
130
131   if(!notice || !name) return;
132
133   list_add_notice(notice);
134
135   newnode = (TimeNode *)malloc(sizeof(TimeNode));
136   buf = (char *)malloc(strlen(name) + 1);
137
138   strcpy(buf, name);
139
140 #ifdef DEBUG_TIMEQUEUE
141   fprintf(stderr, "name: %s\n", buf);
142 #endif
143
144   newnode->when = eventtime;
145   newnode->event_name = buf;
146   newnode->notice = notice;
147
148   timeq_head = addtimenode(timeq_head, newnode);
149 #ifdef DEBUG_TIMEQUEUE
150   fprintf(stderr, "end schedule_event()\n");
151 #endif
152 }
153
154 void 
155 free_timenode(node)
156   TimeNode *node;
157 {
158 #ifdef DEBUG_TIMEQUEUE
159   fprintf(stderr, "free_timenode(%s)\n", node->event_name);
160 #endif
161
162   free(node->event_name);
163   free(node);
164 }
165
166 /* returns the number of notices destroyed */
167 int 
168 destroy_timeq_notice(notice, name)
169   ZNotice_t *notice;
170   char *name;
171 {
172   TimeNode *curr = timeq_head;
173   TimeNode *prev = NULL;
174   TimeNode *tmp;
175
176   int ct = 0;
177
178 #ifdef DEBUG_TIMEQUEUE
179   fprintf(stderr, "destroy_timeq_notice(%s)\n", name);
180 #endif
181
182   while(curr != NULL) {
183     if(curr->notice == notice &&
184        (!name || !strcmp(curr->event_name, name)))
185       {
186         ct++;
187         if(!prev) {
188           timeq_head = curr->next;
189         } else {
190           prev->next = curr->next;
191         }
192         tmp = curr;
193         curr = curr->next;
194         free_timenode(tmp);
195       } else {
196         prev = curr;
197         curr = curr->next;
198       }
199   }
200   
201   return ct;
202 }
203
204 long 
205 plus_timequeue_events()
206
207   /* returns number of seconds to the next event or 0L */
208   /* if there are no events remaining to be processed */
209
210   time_t timenow = time(NULL);
211   TimeNode *curr;
212
213   while(timeq_head != NULL && timeq_head->when <= timenow) {
214 #ifdef DEBUG_TIMEQUEUE
215     fprintf(stderr, "handling event\n");
216 #endif
217     handle_timeq_event(timeq_head);
218     curr = timeq_head;
219     timeq_head = timeq_head->next;
220     free_timenode(curr);
221   }
222
223 #ifdef DEBUG_TIMEQUEUE
224   if(timeq_head != NULL)
225     fprintf(stderr, "next event in %ld seconds.\n",
226        (timeq_head->when) - timenow);
227 #endif
228
229   return ((timeq_head == NULL) ? 0L : ((timeq_head->when) - timenow));
230 }
231
232 void
233 plus_set_hname(notice, hname) 
234   ZNotice_t *notice;
235   char *hname;
236 {
237   notnode *pt;
238   int bx;
239
240   if (hname) {
241     bx = list_hash_fun(notice);
242     for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
243     pt->hname=(char *)malloc(strlen(hname)+1);
244     strcpy(pt->hname, hname);
245   }
246   return;
247 }
248
249 void 
250 plus_queue_notice(notice)
251   ZNotice_t *notice;
252 {
253   char *val;
254   int howlong = 0;
255   
256 #ifdef DEBUG_TIMEQUEUE
257   fprintf(stderr, "plus_queue_notice()\n");
258 #endif
259
260   val = var_get_variable("event_time");
261   if(val) {
262     if(strcmp(val, "kill")) {
263       howlong = atoi(val);
264 #ifdef DEBUG_TIMEQUEUE
265       fprintf(stderr, "$event_time %d\n", howlong);
266 #endif
267     } else {
268       val = var_get_variable("event_name");
269       if(!val || strcmp(val, "all"))
270         destroy_timeq_notice(notice, (val && val[0]) ? val : "event");
271       else
272         destroy_timeq_notice(notice, (char *)NULL);
273     }
274   }
275   
276   if(howlong > 0) {
277     val = var_get_variable("event_name");
278 #ifdef DEBUG_TIMEQUEUE
279     fprintf(stderr, "$event_name = %s\n", val);
280 #endif
281     schedule_event(howlong, (val && val[0]) ? val : "event", notice);
282   }
283 }
284
285 int 
286 list_hash_fun(notice)
287   ZNotice_t *notice;
288 {
289     int ix;
290     int res = 0, val = 1, ptval;
291     char *pt = (char *)(notice);
292
293     for (ix=0; ix<sizeof(ZNotice_t *); ix++) {
294         ptval = (int)pt[ix];
295         if (ptval<0) ptval = (-ptval);
296         res += val * ptval;
297         res %= HASHSIZE;
298         val *= 7;
299     };
300
301     return res;
302 }
303
304 /* initialize hash table */
305 void 
306 init_noticelist()
307 {
308     int ix;
309
310     stored_notice = NULL;
311
312     for (ix=0; ix<HASHSIZE; ix++) {
313         notlist[ix] = NULL;
314     }
315 }
316
317 void 
318 dump_noticelist()
319 {
320     notnode *pt;
321     int bx;
322
323     for (bx=0; bx<HASHSIZE; bx++) {
324         for (pt=notlist[bx]; pt; pt=pt->next) {
325             fprintf(stderr, "Not %p: %d [%d]\n", pt->notice, pt->refcount, bx);
326         }
327     }
328 }
329
330 /* add notice to table. Either generate a new entry, or increment ref count. */
331 void 
332 list_add_notice(notice)
333   ZNotice_t *notice;
334 {
335     notnode *pt;
336     int bx = list_hash_fun(notice);
337
338     for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
339
340     if (pt) {
341         /* found entry */
342         pt->refcount++;
343     }
344     else {
345         /* no entry */
346         pt = (notnode *)malloc(sizeof(notnode));
347         pt->notice = notice;
348         pt->refcount = 1;
349         pt->fake_notice = 0;
350         pt->next = notlist[bx];
351         pt->opcode = notice->z_opcode;
352         pt->hname = NULL;
353         notlist[bx] = pt;
354     }
355
356     /*fprintf(stderr, "list_add_notice(%p)\n", notice);
357     dump_noticelist();*/
358 }   
359
360 /* remove notice from table. If refcount reaches 0, return 1; if refcount is 
361    still positive, return 0; if notice not there, return -1. */
362 int 
363 list_del_notice(notice)
364   ZNotice_t *notice;
365 {
366     notnode *pt, **ppt;
367     int bx = list_hash_fun(notice);
368
369     for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
370
371     if (!pt) {
372         /* no entry */
373         /*fprintf(stderr, "list_del_notice(%p): ERROR\n", notice);
374         dump_noticelist();*/
375         return (-1);
376     }
377
378     pt->refcount--;
379     if (pt->refcount > 0) {
380         /*fprintf(stderr, "list_del_notice(%p): count %d\n", notice, pt->refcount);
381         dump_noticelist();*/
382         return 0;
383     }
384
385     for (ppt = &(notlist[bx]); (*ppt)!=pt; ppt = &((*ppt)->next));
386
387     *ppt = (*ppt)->next;
388
389     if (!pt->fake_notice)
390         ZFreeNotice(pt->notice);
391     if (pt->hname)
392       free(pt->hname);
393     free(pt->notice);
394     free(pt);
395
396     /*fprintf(stderr, "list_del_notice(%p): count 0, gone\n", notice);*/
397     /*dump_noticelist();*/
398     return 1;
399 }
400
401 void 
402 set_notice_fake(notice, val)
403   ZNotice_t *notice;
404   int val;
405 {
406     notnode *pt;
407     int bx = list_hash_fun(notice);
408
409     for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
410
411     if (pt) {
412         pt->fake_notice = val;
413     }
414 }
415
416 int 
417 get_notice_fake(notice)
418   ZNotice_t *notice;
419 {
420     notnode *pt;
421     int bx = list_hash_fun(notice);
422
423     for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
424
425     if (pt) {
426         return pt->fake_notice;
427     }
428     else 
429         return 0;
430 }
431
432 int 
433 get_list_refcount(notice)
434   ZNotice_t *notice;
435 {
436     notnode *pt;
437     int bx = list_hash_fun(notice);
438
439     for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
440
441     if (pt) {
442         /*fprintf(stderr, "get_list_refcount(%p): count %d\n", notice, pt->refcount);*/
443         return pt->refcount;
444     }
445     else {
446         /*fprintf(stderr, "get_list_refcount(%p): count 0\n", notice);*/
447         return 0;
448     }
449 }
450
451 /* export a reference to the current notice. */
452 char 
453 *get_stored_notice()
454 {
455     if (!stored_notice)
456         return NULL;
457
458     list_add_notice(stored_notice);
459
460     return (char *)stored_notice;
461 }
462
463 void 
464 set_stored_notice(notice)
465   ZNotice_t *notice;
466 {
467     stored_notice = notice;
468 }
469
470 void 
471 plus_retry_notice(notice, ch, metaflag)
472   ZNotice_t *notice;
473   char ch;
474   int metaflag;
475 {
476     char buf[128];
477     char *tmp;
478     notnode *pt;
479     int bx;
480
481     if (!notice)
482         return;
483
484     bx = list_hash_fun(notice);
485     for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
486
487     if (metaflag) tmp = "-meta";
488     else tmp = "";
489
490     if (ch==' ')
491         sprintf(buf, "key%s-space", tmp);
492     else if (ch==127)
493         sprintf(buf, "key%s-delete", tmp);
494     else if (ch==0)
495         sprintf(buf, "key%s-ctrl-@", tmp);
496     else if (ch==27)
497         sprintf(buf, "key%s-esc", tmp);
498     else if (isprint(ch))
499         sprintf(buf, "key%s-%c", tmp, ch);
500     else if (ch>=1 && ch<=26)
501         sprintf(buf, "key%s-ctrl-%c", tmp, ch+'a'-1);
502     else if (iscntrl(ch))
503         sprintf(buf, "key%s-ctrl-%c", tmp, ch+'A'-1);
504     else
505         sprintf(buf, "key%s-unknown", tmp);
506
507     /* concat the old opcode if they're running in "new" mode */
508     if (zwgcplus == 2 && pt && pt->opcode[0] && 
509         strcmp(pt->opcode, "") != 0) 
510       {
511         strcat(buf, " ");
512         strncat(buf, pt->opcode, sizeof(buf)-strlen(buf));
513       }
514       
515     notice->z_version = "zwgcplus-repeat";
516     notice->z_opcode = buf;
517
518     reprocess_notice(notice, NULL);
519 }
520 #endif /* CMU_ZWGCPLUS */