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
12 #if (!defined(lint) && !defined(SABER))
13 static const char rcsid_plus_c[] = "$Id: plus.c 2336 2009-03-22 18:59:56Z kcr $";
16 #include <zephyr/mit-copyright.h>
17 #include <zephyr/zephyr.h>
19 #include "new_memory.h"
26 #include "variables.h"
29 #include "xrevstack.h"
33 int get_full_names = 0;
35 #define HASHSIZE (251)
37 typedef struct timenode_s {
39 struct timenode_s *next;
44 typedef struct _notnode {
46 int fake_notice; /* if TRUE, do not call ZFreeNotice() */
48 struct _notnode *next;
53 static ZNotice_t *stored_notice;
54 static notnode *notlist[HASHSIZE];
55 TimeNode *timeq_head = NULL;
57 int list_hash_fun(ZNotice_t *notice);
60 addtimenode(TimeNode *head, TimeNode *node)
63 #ifdef DEBUG_TIMEQUEUE
64 fprintf(stderr, "adding new timenode; creating queue\n");
70 if(head->when > node->when) {
71 #ifdef DEBUG_TIMEQUEUE
72 fprintf(stderr, "adding new timenode at start of queue\n");
78 head->next = addtimenode(head->next, node);
83 handle_timeq_event(TimeNode *event)
87 int bx = list_hash_fun(event->notice);
89 for (pt=notlist[bx]; pt && pt->notice!=event->notice; pt=pt->next);
91 /* "time-" + event_name + '\0' */
92 #ifdef DEBUG_TIMEQUEUE
93 fprintf(stderr, "handle_timeq_event()\n");
96 if (strlen(event->event_name)<123)
97 sprintf(buf, "time-%s", event->event_name);
99 sprintf(buf, "time-bogus");
101 #ifdef DEBUG_TIMEQUEUE
102 fprintf(stderr, "opcode: %s\n", buf);
105 event->notice->z_version = "zwgcplus-repeat";
106 event->notice->z_opcode = buf;
108 reprocess_notice(event->notice, pt->hname);
110 #ifdef DEBUG_TIMEQUEUE
111 fprintf(stderr, "end handle_timeq_event()\n");
116 schedule_event(long secs, char *name, ZNotice_t *notice)
118 time_t eventtime = (time(NULL)) + secs;
122 #ifdef DEBUG_TIMEQUEUE
123 fprintf(stderr, "schedule_event(%ld, %ld, %s)\n", eventtime, secs, name);
126 if(!notice || !name) return;
128 list_add_notice(notice);
130 newnode = (TimeNode *)malloc(sizeof(TimeNode));
131 buf = (char *)malloc(strlen(name) + 1);
135 #ifdef DEBUG_TIMEQUEUE
136 fprintf(stderr, "name: %s\n", buf);
139 newnode->when = eventtime;
140 newnode->event_name = buf;
141 newnode->notice = notice;
143 timeq_head = addtimenode(timeq_head, newnode);
144 #ifdef DEBUG_TIMEQUEUE
145 fprintf(stderr, "end schedule_event()\n");
150 free_timenode(TimeNode *node)
152 #ifdef DEBUG_TIMEQUEUE
153 fprintf(stderr, "free_timenode(%s)\n", node->event_name);
156 free(node->event_name);
160 /* returns the number of notices destroyed */
162 destroy_timeq_notice(ZNotice_t *notice, char *name)
164 TimeNode *curr = timeq_head;
165 TimeNode *prev = NULL;
170 #ifdef DEBUG_TIMEQUEUE
171 fprintf(stderr, "destroy_timeq_notice(%s)\n", name);
174 while(curr != NULL) {
175 if(curr->notice == notice &&
176 (!name || !strcmp(curr->event_name, name)))
180 timeq_head = curr->next;
182 prev->next = curr->next;
197 plus_timequeue_events(void)
199 /* returns number of seconds to the next event or 0L */
200 /* if there are no events remaining to be processed */
202 time_t timenow = time(NULL);
205 while(timeq_head != NULL && timeq_head->when <= timenow) {
206 #ifdef DEBUG_TIMEQUEUE
207 fprintf(stderr, "handling event\n");
209 handle_timeq_event(timeq_head);
211 timeq_head = timeq_head->next;
215 #ifdef DEBUG_TIMEQUEUE
216 if(timeq_head != NULL)
217 fprintf(stderr, "next event in %ld seconds.\n",
218 (timeq_head->when) - timenow);
221 return ((timeq_head == NULL) ? 0L : ((timeq_head->when) - timenow));
225 plus_set_hname(ZNotice_t *notice, char *hname)
231 bx = list_hash_fun(notice);
232 for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
233 pt->hname=(char *)malloc(strlen(hname)+1);
234 strcpy(pt->hname, hname);
240 plus_queue_notice(ZNotice_t *notice)
245 #ifdef DEBUG_TIMEQUEUE
246 fprintf(stderr, "plus_queue_notice()\n");
249 val = var_get_variable("event_time");
251 if(strcmp(val, "kill")) {
253 #ifdef DEBUG_TIMEQUEUE
254 fprintf(stderr, "$event_time %d\n", howlong);
257 val = var_get_variable("event_name");
258 if(!val || strcmp(val, "all"))
259 destroy_timeq_notice(notice, (val && val[0]) ? val : "event");
261 destroy_timeq_notice(notice, (char *)NULL);
266 val = var_get_variable("event_name");
267 #ifdef DEBUG_TIMEQUEUE
268 fprintf(stderr, "$event_name = %s\n", val);
270 schedule_event(howlong, (val && val[0]) ? val : "event", notice);
275 list_hash_fun(ZNotice_t *notice)
278 int res = 0, val = 1, ptval;
279 char *pt = (char *)(notice);
281 for (ix=0; ix<sizeof(ZNotice_t *); ix++) {
283 if (ptval<0) ptval = (-ptval);
292 /* initialize hash table */
294 init_noticelist(void)
298 stored_notice = NULL;
300 for (ix=0; ix<HASHSIZE; ix++) {
306 dump_noticelist(void)
311 for (bx=0; bx<HASHSIZE; bx++) {
312 for (pt=notlist[bx]; pt; pt=pt->next) {
313 fprintf(stderr, "Not %p: %d [%d]\n", pt->notice, pt->refcount, bx);
318 /* add notice to table. Either generate a new entry, or increment ref count. */
320 list_add_notice(ZNotice_t *notice)
323 int bx = list_hash_fun(notice);
325 for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
333 pt = (notnode *)malloc(sizeof(notnode));
337 pt->next = notlist[bx];
338 pt->opcode = notice->z_opcode;
343 /*fprintf(stderr, "list_add_notice(%p)\n", notice);
347 /* remove notice from table. If refcount reaches 0, return 1; if refcount is
348 still positive, return 0; if notice not there, return -1. */
350 list_del_notice(ZNotice_t *notice)
353 int bx = list_hash_fun(notice);
355 for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
359 /*fprintf(stderr, "list_del_notice(%p): ERROR\n", notice);
365 if (pt->refcount > 0) {
366 /*fprintf(stderr, "list_del_notice(%p): count %d\n", notice, pt->refcount);
371 for (ppt = &(notlist[bx]); (*ppt)!=pt; ppt = &((*ppt)->next));
375 if (!pt->fake_notice)
376 ZFreeNotice(pt->notice);
382 /*fprintf(stderr, "list_del_notice(%p): count 0, gone\n", notice);*/
383 /*dump_noticelist();*/
388 set_notice_fake(ZNotice_t *notice, int val)
391 int bx = list_hash_fun(notice);
393 for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
396 pt->fake_notice = val;
401 get_notice_fake(ZNotice_t *notice)
404 int bx = list_hash_fun(notice);
406 for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
409 return pt->fake_notice;
416 get_list_refcount(ZNotice_t *notice)
419 int bx = list_hash_fun(notice);
421 for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
424 /*fprintf(stderr, "get_list_refcount(%p): count %d\n", notice, pt->refcount);*/
428 /*fprintf(stderr, "get_list_refcount(%p): count 0\n", notice);*/
433 /* export a reference to the current notice. */
435 get_stored_notice(void)
440 list_add_notice(stored_notice);
442 return stored_notice;
446 set_stored_notice(ZNotice_t *notice)
448 stored_notice = notice;
452 plus_retry_notice(ZNotice_t *notice, char ch, int metaflag)
462 bx = list_hash_fun(notice);
463 for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
465 if (metaflag) tmp = "-meta";
469 sprintf(buf, "key%s-space", tmp);
471 sprintf(buf, "key%s-delete", tmp);
473 sprintf(buf, "key%s-ctrl-@", tmp);
475 sprintf(buf, "key%s-esc", tmp);
476 else if (isprint(ch))
477 sprintf(buf, "key%s-%c", tmp, ch);
478 else if (ch>=1 && ch<=26)
479 sprintf(buf, "key%s-ctrl-%c", tmp, ch+'a'-1);
480 else if (iscntrl(ch))
481 sprintf(buf, "key%s-ctrl-%c", tmp, ch+'A'-1);
483 sprintf(buf, "key%s-unknown", tmp);
485 /* concat the old opcode if they're running in "new" mode */
486 if (zwgcplus == 2 && pt && pt->opcode[0] &&
487 strcmp(pt->opcode, "") != 0)
490 strncat(buf, pt->opcode, sizeof(buf)-strlen(buf));
493 notice->z_version = "zwgcplus-repeat";
494 notice->z_opcode = buf;
496 reprocess_notice(notice, NULL);
498 #endif /* CMU_ZWGCPLUS */