]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/port.c
0244dac5a6604a8427a22a7fb10fea07d4b7cf4a
[1ts-debian.git] / zephyr / zwgc / port.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It is one of the source files comprising zwgc, the Zephyr WindowGram
3  * client.
4  *
5  *      Created by:     Marc Horowitz <marc@athena.mit.edu>
6  *
7  *      $Id$
8  *
9  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h".
12  */
13
14 #include <sysdep.h>
15
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_port_c[] = "$Id$";
18 #endif
19
20 #include <zephyr/mit-copyright.h>
21
22 /****************************************************************************/
23 /*                                                                          */
24 /*                    The Implementation of the port type:                  */
25 /*                                                                          */
26 /****************************************************************************/
27
28 #include "new_string.h"
29 #include "port_dictionary.h"
30 #include "port.h"
31 #include "notice.h"
32 #include "variables.h"
33
34 /****************************************************************************/
35 /*                                                                          */
36 /*                        Port methods (internal):                          */
37 /*                                                                          */
38 /****************************************************************************/
39
40 static string port_get(p)
41      port *p;
42 {
43     char *(*get_proc)();
44     char *error = NULL;
45     char *result;
46
47     if (p->status & INPUT_CLOSED) {
48         var_set_variable("error",
49                     "Attempt to read from a port whose input has been closed");
50         return(string_Copy(""));
51     }
52
53     get_proc = p->get;
54     if (!get_proc) {
55         var_set_variable("error",
56                  "Attempt to read from a port which does not support reading");
57         return(string_Copy(""));
58     }
59
60     result = get_proc(p, &error);
61     if (!result) {
62         var_set_variable("error", error);
63         return(string_Copy(""));
64     } else
65       return(result);
66 }
67
68 static void port_put(p, data, length)
69      port *p;
70      char *data;
71      int length;
72 {
73     char *(*put_proc)();
74     char *error;
75
76     if (p->status & OUTPUT_CLOSED) {
77         var_set_variable("error",
78                  "Attempt to write to a port whose output has been closed");
79         return;
80     }
81
82     put_proc = p->put;
83     if (!put_proc) {
84         var_set_variable("error",
85                  "Attempt to write to a port which does not support writing");
86         return;
87     }
88
89     error = put_proc(p, data, length);
90     if (error)
91       var_set_variable("error", error);
92 }
93
94 static void port_close_input(p)
95      port *p;
96 {
97     char *(*close_input_proc)();
98     char *error;
99
100     if (p->status & INPUT_CLOSED)
101       return;
102     p->status |= INPUT_CLOSED;
103
104     close_input_proc = p->close_input;
105     if (!close_input_proc)
106       return;
107
108     if (error = close_input_proc(p))
109       var_set_variable("error", error);
110 }
111
112 static void port_close_output(p)
113      port *p;
114 {
115     char *(*close_output_proc)();
116     char *error;
117
118     if (p->status & OUTPUT_CLOSED)
119       return;
120     p->status |= OUTPUT_CLOSED;
121
122     close_output_proc = p->close_output;
123     if (!close_output_proc)
124       return;
125
126     if (error = close_output_proc(p))
127       var_set_variable("error", error);
128 }
129
130 /****************************************************************************/
131 /*                                                                          */
132 /*                 Code to implement a namespace of ports:                  */
133 /*                                                                          */
134 /****************************************************************************/
135
136 /*
137  * port_dict - the dictionary mapping portnames to ports
138  */
139
140 static port_dictionary port_dict = NULL;
141
142 /*
143  *    void init_ports()
144  *        Modifies: all ports
145  *        Effects: Closes all existing ports.  Must be called before
146  *                 any other port call is made.
147  */
148
149 static void close_port_from_binding(b)
150      port_dictionary_binding *b;
151 {
152     port_close_input(&(b->value));
153     port_close_output(&(b->value));
154 }
155
156 void init_ports()
157 {
158     if (port_dict) {
159         port_dictionary_Enumerate(port_dict, close_port_from_binding);
160         port_dictionary_Destroy(port_dict);
161     }
162
163     port_dict = port_dictionary_Create(31);
164 }
165
166 /*
167  * Internal Routine:
168  *
169  *    port *create_named_port(string name)
170  *        Modifies: the port named name
171  *        Requires: init_ports has been called
172  *        Effects: If a port with name name already exists, it is first
173  *                 closed (& destroyed).  A new unfilled in port is then
174  *                 created and assigned the name name.  Its address is
175  *                 then returned.  It is up to the caller to fill in its
176  *                 various fields correctly.
177  */
178
179 static port *create_named_port(name)
180      string name;
181 {
182     int already_exists;
183     port_dictionary_binding *binding;
184
185     binding = port_dictionary_Define(port_dict, name, &already_exists);
186     if (already_exists) {
187         port_close_input(&(binding->value));
188         port_close_output(&(binding->value));
189     }
190
191     return(&(binding->value));
192 }
193
194 /*
195  * Internal Routine:
196  *
197  *    port *get_named_port(string name)
198  *        Requires: init_ports has been called
199  *        Effects: If there is a port by name name, returns a pointer to
200  *                 it.  Otherwise returns NULL.
201  */
202
203 static port *get_named_port(name)
204      string name;
205 {
206     port_dictionary_binding *binding;
207
208     binding = port_dictionary_Lookup(port_dict, name);
209     if (!binding)
210       return(NULL);
211
212     return(&(binding->value));
213 }
214     
215 /****************************************************************************/
216 /*                                                                          */
217 /*                    External interface to named ports:                    */
218 /*                                                                          */
219 /****************************************************************************/
220
221 /*
222  *    string read_from_port(string name)
223  *        Requires: init_ports has been called
224  *        Modifies: the port named name if any, $error
225  *        Effects: If a port by name name does not exist, sets $error to
226  *                 "No such port" & returns "".  Otherwise, attempts to
227  *                 read from that port.  If an error occurs, $error is
228  *                 set to the error message and "" returned.  Otherwise
229  *                 the read string is returned.  The returned string is
230  *                 on the heap & must be eventually freed.
231  */
232
233 string read_from_port(name)
234      string name;
235 {
236     port *p;
237
238     if (!(p = get_named_port(name))) {
239         var_set_variable("error", "No such port");
240         return(string_Copy(""));
241     }
242
243     return(port_get(p));
244 }
245
246 /*
247  *    void write_on_port(string name, char *text, int length)
248  *        Requires: init_ports has been called, length>=0
249  *        Modifies: the port named name if any, $error
250  *        Effects: If a port by name name does not exist, sets $error to
251  *                 "No such port" & returns.  Otherwise, attempts to
252  *                 write text[0..length-1] on that port.  If an error
253  *                 occurs, $error is set to the error message.
254  */
255
256 void write_on_port(name, text, length)
257      string name;
258      char *text;
259      int length;
260 {
261     port *p;
262
263     if (!(p = get_named_port(name))) {
264         var_set_variable("error", "No such port");
265         return;
266     }
267
268     port_put(p, text, length);
269 }
270
271 /*
272  *    void close_port_input(string name)
273  *        Requires: init_ports has been called
274  *        Modifies: the port named name if any, $error
275  *        Effects: If a port by name name does not exist, sets $error to
276  *                 "No such port" & returns.  Otherwise, closes the
277  *                 input part of the port by name name.  When both a
278  *                 port's input & output parts have been closed, the
279  *                 port is deleted to save space.  If an error
280  *                 occurs, $error is set to the error message.
281  */
282
283 void close_port_input(name)
284      string name;
285 {
286     port_dictionary_binding *binding;
287
288     binding = port_dictionary_Lookup(port_dict, name);
289     if (!binding)
290       return;
291
292     port_close_input(&(binding->value));
293     if (binding->value.status == PORT_CLOSED)
294       port_dictionary_Delete(port_dict, binding);
295 }
296
297 /*
298  *    void close_port_output(string name)
299  *        Requires: init_ports has been called
300  *        Modifies: the port named name if any, $error
301  *        Effects: If a port by name name does not exist, sets $error to
302  *                 "No such port" & returns.  Otherwise, closes the
303  *                 output part of the port by name name.  When both a
304  *                 port's input & output parts have been closed, the
305  *                 port is deleted to save space.  If an error
306  *                 occurs, $error is set to the error message.
307  */
308
309 void close_port_output(name)
310      string name;
311 {
312     port_dictionary_binding *binding;
313
314     binding = port_dictionary_Lookup(port_dict, name);
315     if (!binding)
316       return;
317
318     port_close_output(&(binding->value));
319     if (binding->value.status == PORT_CLOSED)
320       port_dictionary_Delete(port_dict, binding);
321 }
322
323 /****************************************************************************/
324 /*                                                                          */
325 /*               Code to implement a port given some FILE *'s:              */
326 /*                                                                          */
327 /****************************************************************************/
328
329 static string get_file(p, error_p)
330      port *p;
331      char **error_p;
332 {
333     char buffer[10000]; /* <<<>>> */
334
335     if (!p->data.file.input_connector) {
336         *error_p = "Attempt to read past end of file";
337         return(NULL);
338     }
339
340     buffer[0] = 0;
341     errno = 0;
342     if (!fgets(buffer, 9999, p->data.file.input_connector)) {
343         if (errno)
344           *error_p = strerror(errno);
345         else
346           *error_p = "Attempt to read past end of file";
347
348         return(NULL);
349     }
350
351     buffer[9999] = 0;
352     return(string_Copy(buffer));
353 }
354
355 static char *put_file(p, text, length)
356      port *p;
357      string text;
358      int length;
359 {
360     if (!p->data.file.output_connector)
361       return(NULL);
362
363     errno = 0;
364     fwrite(text, 1, length, p->data.file.output_connector);
365     fflush(p->data.file.output_connector);
366
367     if (errno)
368       return(strerror(errno));
369
370     return(NULL);
371 }
372
373 static char *close_file_input(p)
374      port *p;
375 {
376     errno = 0;
377     if (p->data.file.input_connector) {
378         fclose(p->data.file.input_connector);
379         p->data.file.input_connector = 0;
380     }
381
382     if (errno)
383       return(strerror(errno));
384
385     return(NULL);
386 }
387
388 static char *close_file_output(p)
389      port *p;
390 {
391     errno = 0;
392     if (p->data.file.output_connector) {
393         fclose(p->data.file.output_connector);
394         p->data.file.output_connector = 0;
395     }
396
397     if (errno)
398       return(strerror(errno));
399
400     return(NULL);
401 }
402
403 void create_port_from_files(name, input, output)
404      string name;
405      FILE *input;
406      FILE *output;
407 {
408     port *p = create_named_port(name);
409
410 #if !defined(__HIGHC__)
411     p->get = input ? get_file : NULL;
412     p->put = output ? put_file : NULL;
413 #else
414     /* RT compiler (hc2.1y) bug workaround */
415     if (input)
416         p->get = get_file;
417     else
418         p->get = NULL;
419     if (output)
420         p->put = put_file;
421     else
422         p->put = NULL;
423 #endif
424     p->close_input = close_file_input;
425     p->close_output = close_file_output;
426     p->status = 0;
427     p->data.file.input_connector = input;
428     p->data.file.output_connector = output;
429 }
430
431 /****************************************************************************/
432 /*                                                                          */
433 /*            Code for creating various types of FILE * ports:              */
434 /*                                                                          */
435 /****************************************************************************/
436
437 void create_subprocess_port(name, argv)
438      string name;
439      char **argv;
440 {
441     int pid;
442     int to_child_descriptors[2];
443     int to_parent_descriptors[2];
444     FILE *in = 0;
445     FILE *out = 0;
446
447     /* <<<>>> (file leak) */
448     if (pipe(to_child_descriptors)!=0 || pipe(to_parent_descriptors)!=0)
449       return;
450
451     pid = fork();
452     if (pid == -1) {
453         fprintf(stderr, "zwgc: error while attempting to fork: ");
454         perror("");
455         return; /* <<<>>> */
456     } else if (pid == 0) { /* in child */
457         close(0);
458         close(1);
459         dup2(to_child_descriptors[0], 0);
460         dup2(to_parent_descriptors[1], 1);
461         close(to_child_descriptors[1]);
462         close(to_parent_descriptors[0]);
463
464         execvp(argv[0], argv);
465         fprintf(stderr,"zwgc: unable to exec %s: ", argv[0]);
466         perror("");
467         _exit(errno);
468     }
469
470     fcntl(to_parent_descriptors[0], F_SETFD, 1);
471     fcntl(to_child_descriptors[1], F_SETFD, 1);
472     in = fdopen(to_parent_descriptors[0],"r");
473     out = fdopen(to_child_descriptors[1],"w");
474     close(to_child_descriptors[0]);
475     close(to_parent_descriptors[1]);
476
477     create_port_from_files(name, in, out);
478 }
479
480 void create_file_append_port(name, filename)
481      string name;
482      string filename;
483 {
484     FILE *out;
485     int oumask;
486
487     errno = 0;
488
489     oumask = umask(077);                /* allow read/write for us only */
490     out = fopen(filename, "a");
491     (void) umask(oumask);
492     if (out == NULL) {
493         var_set_variable("error", strerror(errno));
494         return;
495     }
496
497     create_port_from_files(name, 0, out);
498 }
499
500 void create_file_input_port(name, filename)
501      string name;
502      string filename;
503 {
504     FILE *in;
505
506     errno = 0;
507     in = fopen(filename, "r");
508     if (in == NULL) {
509         var_set_variable("error", strerror(errno));
510         return;
511     }
512
513     create_port_from_files(name, in, 0);
514 }
515
516 void create_file_output_port(name, filename)
517      string name;
518      string filename;
519 {
520     FILE *out;
521     int oumask;
522
523     errno = 0;
524
525     oumask = umask(077);                /* allow read/write for us only */
526     out = fopen(filename, "w");
527     (void) umask(oumask);
528     if (out == NULL) {
529         var_set_variable("error", strerror(errno));
530         return;
531     }
532
533     create_port_from_files(name, 0, out);
534 }
535
536 /****************************************************************************/
537 /*                                                                          */
538 /*             Code to implement a port given a filter function:            */
539 /*                                                                          */
540 /****************************************************************************/
541
542 static string get_filter(p, error_p)
543      port *p;
544      char **error_p;
545 {
546     string result;
547
548     if (string_stack_empty(p->data.filter.waiting_packets)) {
549         *error_p = "Attempt to read from port when no data available";
550         return(NULL);
551     }
552
553     result = string_stack_top(p->data.filter.waiting_packets);
554     string_stack_pop(p->data.filter.waiting_packets);
555     return(result);
556 }
557
558 static char *put_filter(p, text, length)
559      port *p;
560      string text;
561      int length;
562 {
563     string input;
564     string output;
565
566     if (p->status & INPUT_CLOSED)
567       return(NULL);
568
569     input = convert_nulls_to_newlines(text, length);
570     output = (*(p->data.filter.filter))(input);
571     free(input);
572     string_stack_push(p->data.filter.waiting_packets, output);
573     return(NULL);
574 }
575
576 static char *close_filter_input(p)
577      port *p;
578 {
579     while (!string_stack_empty(p->data.filter.waiting_packets))
580       string_stack_pop(p->data.filter.waiting_packets);
581
582     return(NULL);
583 }
584
585 /*ARGSUSED*/
586 static char *close_filter_output(p)
587      port *p;
588 {
589     return(NULL);
590 }
591
592 void create_port_from_filter(name, filter)
593      string name;
594      string (*filter)();
595 {
596     port *p = create_named_port(name);
597
598     p->get = get_filter;
599     p->put = put_filter;
600     p->close_input = close_filter_input;
601     p->close_output = close_filter_output;
602     p->status = 0;
603     p->data.filter.waiting_packets = string_stack_create();
604     p->data.filter.filter = filter;
605 }
606
607 /****************************************************************************/
608 /*                                                                          */
609 /*             Code to implement a port given an output function:           */
610 /*                                                                          */
611 /****************************************************************************/
612
613 static char *put_output(p, text, length)
614      port *p;
615      string text;
616      int length;
617 {
618     string input;
619     char *error;
620
621     input = convert_nulls_to_newlines(text, length);
622     error = p->data.output.output(input);
623     free(input);
624     return(error);
625 }
626
627 /*ARGSUSED*/
628 static char *close_output(p)
629      port *p;
630 {
631     return(NULL);
632 }
633
634 void create_port_from_output_proc(name, output)
635      string name;
636      char *(*output)();
637 {
638 #ifdef SABER /* Yes, it's another ANSI incompatiblity */
639     port *p;
640 #else
641     port *p = create_named_port(name);
642 #endif
643
644 #ifdef SABER
645     p = create_named_port(name);
646 #endif
647
648     p->get = NULL;
649     p->put = put_output;
650     p->close_input = close_output;
651     p->close_output = close_output;
652     p->status = 0;
653     p->data.output.output = output;
654 }