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