Jabber WindowGram Client (JWGC)

Introduction Screenshots Installation Downloads
Documentation Browse Source Resources Project Site

Stable Version
-none-

Latest Version
beta5



Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

port.c

Go to the documentation of this file.
00001 /*
00002  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
00003  *      For copying and distribution information, see the file
00004  *      "mit-copyright.h".
00005  *
00006  *      Modified for jwgc by Daniel Henninger.
00007  */
00008 
00009 #include "mit-copyright.h"
00010 
00011 /****************************************************************************/
00012 /* */
00013 /* The Implementation of the port type:                  */
00014 /* */
00015 /****************************************************************************/
00016 
00017 #include "main.h"
00018 #include "new_string.h"
00019 #include "port_dictionary.h"
00020 #include "port.h"
00021 #include "notice.h"
00022 #include "variables.h"
00023 
00024 /****************************************************************************/
00025 /* */
00026 /* Port methods (internal):                          */
00027 /* */
00028 /****************************************************************************/
00029 
00030 static string 
00031 port_get(p)
00032         port *p;
00033 {
00034         char *(*get_proc) ();
00035         char *error = NULL;
00036         char *result;
00037 
00038         if (p->status & INPUT_CLOSED) {
00039                 var_set_variable("error",
00040                  "Attempt to read from a port whose input has been closed");
00041                 return (string_Copy(""));
00042         }
00043 
00044         get_proc = p->get;
00045         if (!get_proc) {
00046                 var_set_variable("error",
00047                                  "Attempt to read from a port which does not support reading");
00048                 return (string_Copy(""));
00049         }
00050 
00051         result = get_proc(p, &error);
00052         if (!result) {
00053                 var_set_variable("error", error);
00054                 return (string_Copy(""));
00055         }
00056         else
00057                 return (result);
00058 }
00059 
00060 static void 
00061 port_put(p, data, length)
00062         port *p;
00063         char *data;
00064         int length;
00065 {
00066         char *(*put_proc) ();
00067         char *error;
00068 
00069         if (p->status & OUTPUT_CLOSED) {
00070                 var_set_variable("error",
00071                  "Attempt to write to a port whose output has been closed");
00072                 return;
00073         }
00074 
00075         put_proc = p->put;
00076         if (!put_proc) {
00077                 var_set_variable("error",
00078                 "Attempt to write to a port which does not support writing");
00079                 return;
00080         }
00081 
00082         error = put_proc(p, data, length);
00083         if (error)
00084                 var_set_variable("error", error);
00085 }
00086 
00087 static void 
00088 port_close_input(p)
00089         port *p;
00090 {
00091         char *(*close_input_proc) ();
00092         char *error;
00093 
00094         if (p->status & INPUT_CLOSED)
00095                 return;
00096         p->status |= INPUT_CLOSED;
00097 
00098         close_input_proc = p->close_input;
00099         if (!close_input_proc)
00100                 return;
00101 
00102         if ((error = close_input_proc(p)))
00103                 var_set_variable("error", error);
00104 }
00105 
00106 static void 
00107 port_close_output(p)
00108         port *p;
00109 {
00110         char *(*close_output_proc) ();
00111         char *error;
00112 
00113         if (p->status & OUTPUT_CLOSED)
00114                 return;
00115         p->status |= OUTPUT_CLOSED;
00116 
00117         close_output_proc = p->close_output;
00118         if (!close_output_proc)
00119                 return;
00120 
00121         if ((error = close_output_proc(p)))
00122                 var_set_variable("error", error);
00123 }
00124 
00125 /****************************************************************************/
00126 /* */
00127 /* Code to implement a namespace of ports:                  */
00128 /* */
00129 /****************************************************************************/
00130 
00131 /*
00132  * port_dict - the dictionary mapping portnames to ports
00133  */
00134 
00135 static port_dictionary port_dict = NULL;
00136 
00137 /*
00138  *    void init_ports()
00139  *        Modifies: all ports
00140  *        Effects: Closes all existing ports.  Must be called before
00141  *                 any other port call is made.
00142  */
00143 
00144 static void 
00145 close_port_from_binding(b)
00146         port_dictionary_binding *b;
00147 {
00148         port_close_input(&(b->value));
00149         port_close_output(&(b->value));
00150 }
00151 
00152 void 
00153 init_ports()
00154 {
00155         if (port_dict) {
00156                 port_dictionary_Enumerate(port_dict, close_port_from_binding);
00157                 port_dictionary_Destroy(port_dict);
00158         }
00159 
00160         port_dict = port_dictionary_Create(31);
00161 }
00162 
00163 /*
00164  * Internal Routine:
00165  *
00166  *    port *create_named_port(string name)
00167  *        Modifies: the port named name
00168  *        Requires: init_ports has been called
00169  *        Effects: If a port with name name already exists, it is first
00170  *                 closed (& destroyed).  A new unfilled in port is then
00171  *                 created and assigned the name name.  Its address is
00172  *                 then returned.  It is up to the caller to fill in its
00173  *                 various fields correctly.
00174  */
00175 
00176 static port *
00177 create_named_port(name)
00178         string name;
00179 {
00180         int already_exists;
00181         port_dictionary_binding *binding;
00182 
00183         binding = port_dictionary_Define(port_dict, name, &already_exists);
00184         if (already_exists) {
00185                 port_close_input(&(binding->value));
00186                 port_close_output(&(binding->value));
00187         }
00188 
00189         return (&(binding->value));
00190 }
00191 
00192 /*
00193  * Internal Routine:
00194  *
00195  *    port *get_named_port(string name)
00196  *        Requires: init_ports has been called
00197  *        Effects: If there is a port by name name, returns a pointer to
00198  *                 it.  Otherwise returns NULL.
00199  */
00200 
00201 static port *
00202 get_named_port(name)
00203         string name;
00204 {
00205         port_dictionary_binding *binding;
00206 
00207         binding = port_dictionary_Lookup(port_dict, name);
00208         if (!binding)
00209                 return (NULL);
00210 
00211         return (&(binding->value));
00212 }
00213 
00214 /****************************************************************************/
00215 /* */
00216 /* External interface to named ports:                    */
00217 /* */
00218 /****************************************************************************/
00219 
00220 /*
00221  *    string read_from_port(string name)
00222  *        Requires: init_ports has been called
00223  *        Modifies: the port named name if any, $error
00224  *        Effects: If a port by name name does not exist, sets $error to
00225  *                 "No such port" & returns "".  Otherwise, attempts to
00226  *                 read from that port.  If an error occurs, $error is
00227  *                 set to the error message and "" returned.  Otherwise
00228  *                 the read string is returned.  The returned string is
00229  *                 on the heap & must be eventually freed.
00230  */
00231 
00232 string 
00233 read_from_port(name)
00234         string name;
00235 {
00236         port *p;
00237 
00238         if (!(p = get_named_port(name))) {
00239                 var_set_variable("error", "No such port");
00240                 return (string_Copy(""));
00241         }
00242 
00243         return (port_get(p));
00244 }
00245 
00246 /*
00247  *    void write_on_port(string name, char *text, int length)
00248  *        Requires: init_ports has been called, length>=0
00249  *        Modifies: the port named name if any, $error
00250  *        Effects: If a port by name name does not exist, sets $error to
00251  *                 "No such port" & returns.  Otherwise, attempts to
00252  *                 write text[0..length-1] on that port.  If an error
00253  *                 occurs, $error is set to the error message.
00254  */
00255 
00256 void 
00257 write_on_port(name, text, length)
00258         string name;
00259         char *text;
00260         int length;
00261 {
00262         port *p;
00263 
00264         if (!(p = get_named_port(name))) {
00265                 var_set_variable("error", "No such port");
00266                 return;
00267         }
00268 
00269         port_put(p, text, length);
00270 }
00271 
00272 /*
00273  *    void close_port_input(string name)
00274  *        Requires: init_ports has been called
00275  *        Modifies: the port named name if any, $error
00276  *        Effects: If a port by name name does not exist, sets $error to
00277  *                 "No such port" & returns.  Otherwise, closes the
00278  *                 input part of the port by name name.  When both a
00279  *                 port's input & output parts have been closed, the
00280  *                 port is deleted to save space.  If an error
00281  *                 occurs, $error is set to the error message.
00282  */
00283 
00284 void 
00285 close_port_input(name)
00286         string name;
00287 {
00288         port_dictionary_binding *binding;
00289 
00290         binding = port_dictionary_Lookup(port_dict, name);
00291         if (!binding)
00292                 return;
00293 
00294         port_close_input(&(binding->value));
00295         if (binding->value.status == PORT_CLOSED)
00296                 port_dictionary_Delete(port_dict, binding);
00297 }
00298 
00299 /*
00300  *    void close_port_output(string name)
00301  *        Requires: init_ports has been called
00302  *        Modifies: the port named name if any, $error
00303  *        Effects: If a port by name name does not exist, sets $error to
00304  *                 "No such port" & returns.  Otherwise, closes the
00305  *                 output part of the port by name name.  When both a
00306  *                 port's input & output parts have been closed, the
00307  *                 port is deleted to save space.  If an error
00308  *                 occurs, $error is set to the error message.
00309  */
00310 
00311 void 
00312 close_port_output(name)
00313         string name;
00314 {
00315         port_dictionary_binding *binding;
00316 
00317         binding = port_dictionary_Lookup(port_dict, name);
00318         if (!binding)
00319                 return;
00320 
00321         port_close_output(&(binding->value));
00322         if (binding->value.status == PORT_CLOSED)
00323                 port_dictionary_Delete(port_dict, binding);
00324 }
00325 
00326 /****************************************************************************/
00327 /* */
00328 /* Code to implement a port given some FILE *'s:              */
00329 /* */
00330 /****************************************************************************/
00331 
00332 static string 
00333 get_file(p, error_p)
00334         port *p;
00335         char **error_p;
00336 {
00337         char buffer[10000];     /* <<<>>> */
00338 
00339         if (!p->data.file.input_connector) {
00340                 *error_p = "Attempt to read past end of file";
00341                 return (NULL);
00342         }
00343 
00344         buffer[0] = 0;
00345         errno = 0;
00346         if (!fgets(buffer, 9999, p->data.file.input_connector)) {
00347                 if (errno)
00348                         *error_p = strerror(errno);
00349                 else
00350                         *error_p = "Attempt to read past end of file";
00351 
00352                 return (NULL);
00353         }
00354 
00355         buffer[9999] = 0;
00356         return (string_Copy(buffer));
00357 }
00358 
00359 static char *
00360 put_file(p, text, length)
00361         port *p;
00362         string text;
00363         int length;
00364 {
00365         if (!p->data.file.output_connector)
00366                 return (NULL);
00367 
00368         errno = 0;
00369         fwrite(text, 1, length, p->data.file.output_connector);
00370         fflush(p->data.file.output_connector);
00371 
00372         if (errno)
00373                 return (strerror(errno));
00374 
00375         return (NULL);
00376 }
00377 
00378 static char *
00379 close_file_input(p)
00380         port *p;
00381 {
00382         errno = 0;
00383         if (p->data.file.input_connector) {
00384                 fclose(p->data.file.input_connector);
00385                 p->data.file.input_connector = 0;
00386         }
00387 
00388         if (errno)
00389                 return (strerror(errno));
00390 
00391         return (NULL);
00392 }
00393 
00394 static char *
00395 close_file_output(p)
00396         port *p;
00397 {
00398         errno = 0;
00399         if (p->data.file.output_connector) {
00400                 fclose(p->data.file.output_connector);
00401                 p->data.file.output_connector = 0;
00402         }
00403 
00404         if (errno)
00405                 return (strerror(errno));
00406 
00407         return (NULL);
00408 }
00409 
00410 void 
00411 create_port_from_files(name, input, output)
00412         string name;
00413         FILE *input;
00414         FILE *output;
00415 {
00416         port *p = create_named_port(name);
00417 
00418 #if !defined(__HIGHC__)
00419         p->get = input ? get_file : NULL;
00420         p->put = output ? put_file : NULL;
00421 #else
00422         /* RT compiler (hc2.1y) bug workaround */
00423         if (input)
00424                 p->get = get_file;
00425         else
00426                 p->get = NULL;
00427         if (output)
00428                 p->put = put_file;
00429         else
00430                 p->put = NULL;
00431 #endif
00432         p->close_input = close_file_input;
00433         p->close_output = close_file_output;
00434         p->status = 0;
00435         p->data.file.input_connector = input;
00436         p->data.file.output_connector = output;
00437 }
00438 
00439 /****************************************************************************/
00440 /* */
00441 /* Code for creating various types of FILE * ports:              */
00442 /* */
00443 /****************************************************************************/
00444 
00445 void 
00446 create_subprocess_port(name, argv)
00447         string name;
00448         char **argv;
00449 {
00450         int pid;
00451         int to_child_descriptors[2];
00452         int to_parent_descriptors[2];
00453         FILE *in = 0;
00454         FILE *out = 0;
00455 
00456         /* <<<>>> (file leak) */
00457         if (pipe(to_child_descriptors) != 0 || pipe(to_parent_descriptors) != 0)
00458                 return;
00459 
00460         pid = fork();
00461         if (pid == -1) {
00462                 fprintf(stderr, "jwgc: error while attempting to fork: ");
00463                 perror("");
00464                 return;         /* <<<>>> */
00465         }
00466         else if (pid == 0) {    /* in child */
00467                 close(0);
00468                 close(1);
00469                 dup2(to_child_descriptors[0], 0);
00470                 dup2(to_parent_descriptors[1], 1);
00471                 close(to_child_descriptors[1]);
00472                 close(to_parent_descriptors[0]);
00473 
00474                 execvp(argv[0], argv);
00475                 fprintf(stderr, "jwgc: unable to exec %s: ", argv[0]);
00476                 perror("");
00477                 _exit(errno);
00478         }
00479 
00480         fcntl(to_parent_descriptors[0], F_SETFD, 1);
00481         fcntl(to_child_descriptors[1], F_SETFD, 1);
00482         in = fdopen(to_parent_descriptors[0], "r");
00483         out = fdopen(to_child_descriptors[1], "w");
00484         close(to_child_descriptors[0]);
00485         close(to_parent_descriptors[1]);
00486 
00487         create_port_from_files(name, in, out);
00488 }
00489 
00490 void 
00491 create_file_append_port(name, filename)
00492         string name;
00493         string filename;
00494 {
00495         FILE *out;
00496         int oumask;
00497 
00498         errno = 0;
00499 
00500         oumask = umask(077);    /* allow read/write for us only */
00501         out = fopen(filename, "a");
00502         (void) umask(oumask);
00503         if (out == NULL) {
00504                 var_set_variable("error", strerror(errno));
00505                 return;
00506         }
00507 
00508         create_port_from_files(name, 0, out);
00509 }
00510 
00511 void 
00512 create_file_input_port(name, filename)
00513         string name;
00514         string filename;
00515 {
00516         FILE *in;
00517 
00518         errno = 0;
00519         in = fopen(filename, "r");
00520         if (in == NULL) {
00521                 var_set_variable("error", strerror(errno));
00522                 return;
00523         }
00524 
00525         create_port_from_files(name, in, 0);
00526 }
00527 
00528 void 
00529 create_file_output_port(name, filename)
00530         string name;
00531         string filename;
00532 {
00533         FILE *out;
00534         int oumask;
00535 
00536         errno = 0;
00537 
00538         oumask = umask(077);    /* allow read/write for us only */
00539         out = fopen(filename, "w");
00540         (void) umask(oumask);
00541         if (out == NULL) {
00542                 var_set_variable("error", strerror(errno));
00543                 return;
00544         }
00545 
00546         create_port_from_files(name, 0, out);
00547 }
00548 
00549 /****************************************************************************/
00550 /* */
00551 /* Code to implement a port given a filter function:            */
00552 /* */
00553 /****************************************************************************/
00554 
00555 static string 
00556 get_filter(p, error_p)
00557         port *p;
00558         char **error_p;
00559 {
00560         string result;
00561 
00562         if (string_stack_empty(p->data.filter.waiting_packets)) {
00563                 *error_p = "Attempt to read from port when no data available";
00564                 return (NULL);
00565         }
00566 
00567         result = string_stack_top(p->data.filter.waiting_packets);
00568         string_stack_pop(p->data.filter.waiting_packets);
00569         return (result);
00570 }
00571 
00572 static char *
00573 put_filter(p, text, length)
00574         port *p;
00575         string text;
00576         int length;
00577 {
00578         string input;
00579         string output;
00580 
00581         if (p->status & INPUT_CLOSED)
00582                 return (NULL);
00583 
00584         input = convert_nulls_to_newlines(text, length);
00585         output = (*(p->data.filter.filter)) (input);
00586         free(input);
00587         string_stack_push(p->data.filter.waiting_packets, output);
00588         return (NULL);
00589 }
00590 
00591 static char *
00592 close_filter_input(p)
00593         port *p;
00594 {
00595         while (!string_stack_empty(p->data.filter.waiting_packets))
00596                 string_stack_pop(p->data.filter.waiting_packets);
00597 
00598         return (NULL);
00599 }
00600 
00601 /* ARGSUSED */
00602 static char *
00603 close_filter_output(p)
00604         port *p;
00605 {
00606         return (NULL);
00607 }
00608 
00609 void 
00610 create_port_from_filter(name, filter)
00611         string name;
00612 string(*filter) ();
00613 {
00614         port *p = create_named_port(name);
00615 
00616         p->get = get_filter;
00617         p->put = put_filter;
00618         p->close_input = close_filter_input;
00619         p->close_output = close_filter_output;
00620         p->status = 0;
00621         p->data.filter.waiting_packets = string_stack_create();
00622         p->data.filter.filter = filter;
00623 }
00624 
00625 /****************************************************************************/
00626 /* */
00627 /* Code to implement a port given an output function:           */
00628 /* */
00629 /****************************************************************************/
00630 
00631 static char *
00632 put_output(p, text, length)
00633         port *p;
00634         string text;
00635         int length;
00636 {
00637         string input;
00638         char *error;
00639 
00640         input = convert_nulls_to_newlines(text, length);
00641         error = p->data.output.output(input);
00642         free(input);
00643         return (error);
00644 }
00645 
00646 /* ARGSUSED */
00647 static char *
00648 close_output(p)
00649         port *p;
00650 {
00651         return (NULL);
00652 }
00653 
00654 void 
00655 create_port_from_output_proc(name, output)
00656         string name;
00657         char *(*output) ();
00658 {
00659 #ifdef SABER                    /* Yes, it's another ANSI incompatiblity */
00660         port *p;
00661 #else
00662         port *p = create_named_port(name);
00663 #endif
00664 
00665 #ifdef SABER
00666         p = create_named_port(name);
00667 #endif
00668 
00669         p->get = NULL;
00670         p->put = put_output;
00671         p->close_input = close_output;
00672         p->close_output = close_output;
00673         p->status = 0;
00674         p->data.output.output = output;
00675 }


Last updated at Tue Dec 18 21:07:42 PST 2007. This site and project hosted by...SourceForge.net Logo
Source Perspective by Fisheye