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
5 * Created by: Marc Horowitz <marc@athena.mit.edu>
7 * $Id: port.c 2144 2008-01-21 07:57:32Z kcr $
9 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_port_c[] = "$Id: port.c 2144 2008-01-21 07:57:32Z kcr $";
20 #include <zephyr/mit-copyright.h>
22 /****************************************************************************/
24 /* The Implementation of the port type: */
26 /****************************************************************************/
28 #include "new_string.h"
29 #include "port_dictionary.h"
32 #include "variables.h"
34 /****************************************************************************/
36 /* Port methods (internal): */
38 /****************************************************************************/
43 char *(*get_proc)(port *, char **);
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(""));
55 var_set_variable("error",
56 "Attempt to read from a port which does not support reading");
57 return(string_Copy(""));
60 result = get_proc(p, &error);
62 var_set_variable("error", error);
63 return(string_Copy(""));
73 char *(*put_proc)(port *, char *, int);
76 if (p->status & OUTPUT_CLOSED) {
77 var_set_variable("error",
78 "Attempt to write to a port whose output has been closed");
84 var_set_variable("error",
85 "Attempt to write to a port which does not support writing");
89 error = put_proc(p, data, length);
91 var_set_variable("error", error);
95 port_close_input(port *p)
97 char *(*close_input_proc)(port *);
100 if (p->status & INPUT_CLOSED)
102 p->status |= INPUT_CLOSED;
104 close_input_proc = p->close_input;
105 if (!close_input_proc)
108 error = close_input_proc(p);
110 var_set_variable("error", error);
114 port_close_output(port *p)
116 char *(*close_output_proc)(port *);
119 if (p->status & OUTPUT_CLOSED)
121 p->status |= OUTPUT_CLOSED;
123 close_output_proc = p->close_output;
124 if (!close_output_proc)
127 error = close_output_proc(p);
129 var_set_variable("error", error);
132 /****************************************************************************/
134 /* Code to implement a namespace of ports: */
136 /****************************************************************************/
139 * port_dict - the dictionary mapping portnames to ports
142 static port_dictionary port_dict = NULL;
146 * Modifies: all ports
147 * Effects: Closes all existing ports. Must be called before
148 * any other port call is made.
152 close_port_from_binding(port_dictionary_binding *b)
154 port_close_input(&(b->value));
155 port_close_output(&(b->value));
162 port_dictionary_Enumerate(port_dict, close_port_from_binding);
163 port_dictionary_Destroy(port_dict);
166 port_dict = port_dictionary_Create(31);
172 * port *create_named_port(string name)
173 * Modifies: the port named name
174 * Requires: init_ports has been called
175 * Effects: If a port with name name already exists, it is first
176 * closed (& destroyed). A new unfilled in port is then
177 * created and assigned the name name. Its address is
178 * then returned. It is up to the caller to fill in its
179 * various fields correctly.
183 create_named_port(string name)
186 port_dictionary_binding *binding;
188 binding = port_dictionary_Define(port_dict, name, &already_exists);
189 if (already_exists) {
190 port_close_input(&(binding->value));
191 port_close_output(&(binding->value));
194 return(&(binding->value));
200 * port *get_named_port(string name)
201 * Requires: init_ports has been called
202 * Effects: If there is a port by name name, returns a pointer to
203 * it. Otherwise returns NULL.
207 get_named_port(string name)
209 port_dictionary_binding *binding;
211 binding = port_dictionary_Lookup(port_dict, name);
215 return(&(binding->value));
218 /****************************************************************************/
220 /* External interface to named ports: */
222 /****************************************************************************/
225 * string read_from_port(string name)
226 * Requires: init_ports has been called
227 * Modifies: the port named name if any, $error
228 * Effects: If a port by name name does not exist, sets $error to
229 * "No such port" & returns "". Otherwise, attempts to
230 * read from that port. If an error occurs, $error is
231 * set to the error message and "" returned. Otherwise
232 * the read string is returned. The returned string is
233 * on the heap & must be eventually freed.
237 read_from_port(string name)
241 if (!(p = get_named_port(name))) {
242 var_set_variable("error", "No such port");
243 return(string_Copy(""));
250 * void write_on_port(string name, char *text, int length)
251 * Requires: init_ports has been called, length>=0
252 * Modifies: the port named name if any, $error
253 * Effects: If a port by name name does not exist, sets $error to
254 * "No such port" & returns. Otherwise, attempts to
255 * write text[0..length-1] on that port. If an error
256 * occurs, $error is set to the error message.
260 write_on_port(string name,
266 if (!(p = get_named_port(name))) {
267 var_set_variable("error", "No such port");
271 port_put(p, text, length);
275 * void close_port_input(string name)
276 * Requires: init_ports has been called
277 * Modifies: the port named name if any, $error
278 * Effects: If a port by name name does not exist, sets $error to
279 * "No such port" & returns. Otherwise, closes the
280 * input part of the port by name name. When both a
281 * port's input & output parts have been closed, the
282 * port is deleted to save space. If an error
283 * occurs, $error is set to the error message.
287 close_port_input(string name)
289 port_dictionary_binding *binding;
291 binding = port_dictionary_Lookup(port_dict, name);
295 port_close_input(&(binding->value));
296 if (binding->value.status == PORT_CLOSED)
297 port_dictionary_Delete(port_dict, binding);
301 * void close_port_output(string name)
302 * Requires: init_ports has been called
303 * Modifies: the port named name if any, $error
304 * Effects: If a port by name name does not exist, sets $error to
305 * "No such port" & returns. Otherwise, closes the
306 * output part of the port by name name. When both a
307 * port's input & output parts have been closed, the
308 * port is deleted to save space. If an error
309 * occurs, $error is set to the error message.
313 close_port_output(string name)
315 port_dictionary_binding *binding;
317 binding = port_dictionary_Lookup(port_dict, name);
321 port_close_output(&(binding->value));
322 if (binding->value.status == PORT_CLOSED)
323 port_dictionary_Delete(port_dict, binding);
326 /****************************************************************************/
328 /* Code to implement a port given some FILE *'s: */
330 /****************************************************************************/
336 char buffer[10000]; /* <<<>>> */
338 if (!p->data.file.input_connector) {
339 *error_p = "Attempt to read past end of file";
345 if (!fgets(buffer, 9999, p->data.file.input_connector)) {
347 *error_p = strerror(errno);
349 *error_p = "Attempt to read past end of file";
355 return(string_Copy(buffer));
363 if (!p->data.file.output_connector)
367 fwrite(text, 1, length, p->data.file.output_connector);
368 fflush(p->data.file.output_connector);
371 return(strerror(errno));
377 close_file_input(port *p)
380 if (p->data.file.input_connector) {
381 fclose(p->data.file.input_connector);
382 p->data.file.input_connector = 0;
386 return(strerror(errno));
392 close_file_output(port *p)
395 if (p->data.file.output_connector) {
396 fclose(p->data.file.output_connector);
397 p->data.file.output_connector = 0;
401 return(strerror(errno));
406 void create_port_from_files(string name,
410 port *p = create_named_port(name);
412 #if !defined(__HIGHC__)
413 p->get = input ? get_file : NULL;
414 p->put = output ? put_file : NULL;
416 /* RT compiler (hc2.1y) bug workaround */
426 p->close_input = close_file_input;
427 p->close_output = close_file_output;
429 p->data.file.input_connector = input;
430 p->data.file.output_connector = output;
433 /****************************************************************************/
435 /* Code for creating various types of FILE * ports: */
437 /****************************************************************************/
440 create_subprocess_port(string name,
444 int to_child_descriptors[2];
445 int to_parent_descriptors[2];
449 /* <<<>>> (file leak) */
450 if (pipe(to_child_descriptors)!=0 || pipe(to_parent_descriptors)!=0)
455 fprintf(stderr, "zwgc: error while attempting to fork: ");
458 } else if (pid == 0) { /* in child */
461 dup2(to_child_descriptors[0], 0);
462 dup2(to_parent_descriptors[1], 1);
463 close(to_child_descriptors[1]);
464 close(to_parent_descriptors[0]);
466 execvp(argv[0], argv);
467 fprintf(stderr,"zwgc: unable to exec %s: ", argv[0]);
472 fcntl(to_parent_descriptors[0], F_SETFD, 1);
473 fcntl(to_child_descriptors[1], F_SETFD, 1);
474 in = fdopen(to_parent_descriptors[0],"r");
475 out = fdopen(to_child_descriptors[1],"w");
476 close(to_child_descriptors[0]);
477 close(to_parent_descriptors[1]);
479 create_port_from_files(name, in, out);
483 create_file_append_port(string name,
491 oumask = umask(077); /* allow read/write for us only */
492 out = fopen(filename, "a");
493 (void) umask(oumask);
495 var_set_variable("error", strerror(errno));
499 create_port_from_files(name, 0, out);
503 create_file_input_port(string name,
509 in = fopen(filename, "r");
511 var_set_variable("error", strerror(errno));
515 create_port_from_files(name, in, 0);
519 create_file_output_port(string name,
527 oumask = umask(077); /* allow read/write for us only */
528 out = fopen(filename, "w");
529 (void) umask(oumask);
531 var_set_variable("error", strerror(errno));
535 create_port_from_files(name, 0, out);
538 /****************************************************************************/
540 /* Code to implement a port given a filter function: */
542 /****************************************************************************/
550 if (string_stack_empty(p->data.filter.waiting_packets)) {
551 *error_p = "Attempt to read from port when no data available";
555 result = string_stack_top(p->data.filter.waiting_packets);
556 string_stack_pop(p->data.filter.waiting_packets);
568 if (p->status & INPUT_CLOSED)
571 input = convert_nulls_to_newlines(text, length);
572 output = (*(p->data.filter.filter))(input);
574 string_stack_push(p->data.filter.waiting_packets, output);
579 close_filter_input(port *p)
581 while (!string_stack_empty(p->data.filter.waiting_packets))
582 string_stack_pop(p->data.filter.waiting_packets);
589 close_filter_output(port *p)
595 create_port_from_filter(string name,
596 string (*filter)(string))
598 port *p = create_named_port(name);
602 p->close_input = close_filter_input;
603 p->close_output = close_filter_output;
605 p->data.filter.waiting_packets = string_stack_create();
606 p->data.filter.filter = filter;
609 /****************************************************************************/
611 /* Code to implement a port given an output function: */
613 /****************************************************************************/
623 input = convert_nulls_to_newlines(text, length);
624 error = p->data.output.output(input);
631 close_output(port *p)
637 create_port_from_output_proc(string name,
638 char *(*output)(string))
640 #ifdef SABER /* Yes, it's another ANSI incompatiblity */
643 port *p = create_named_port(name);
647 p = create_named_port(name);
652 p->close_input = close_output;
653 p->close_output = close_output;
655 p->data.output.output = output;