Galaxy Communicator Documentation:

Upgrading from 1.2 or 1.3 to 2.0

License / Documentation home / Help and feedback

For most applications, upgrading from 1.2 to 1.3 will be fairly transparent. The release notes should provide enough detail. However, the upgrade from 1.3 to 2.0 is much more complex. Here, we attempt to provide a step-by-step guide to updating your systems.


Step 0: Updating to 1.3

First, be sure you've consulted the release notes for version 1.3 and updated appropriately. Things to watch out for:

Step 1: Configuring your system

In previous releases, someone configuring a Communicator distribution was required to edit three files: templates/init.make, templates/site.make, and templates/links.setenv.<archos>. Each of these files was represented in the distribution by a .in file which had to be copied and modified. Furthermore, the file templates/sysdep.make had additional platform information which interacted with some of these configuration files but had no .in equivalent. Finally, the first two configuration files were Makefiles, while the third was a shell script. In Galaxy Communicator 2.0, all this information is centralized in a single file templates/config.make.in, which also has detailed instructions interleaved. See the installation notes for details.


Step 2: Updating your headers

The Communicator distribution now uses a single header file galaxy/galaxy_all.h. Significantly, the header file sls/util.h has been replaced by galaxy/util.h in the set of headers that Communicator servers use. Change all references to sls/util.h to galaxy/util.h, or better yet, just replace the set of four headers with a single reference to galaxy/galaxy_all.h.


Step 3: Updating your command line argument parsing and printing

The old functions and types stand in a one-to-one correspondence with the new ones; only the names have been changed, to guarantee that the core library won't have symbol clashes with the MIT utilities library and to provide naming consistency.
 
old new
FALSE GAL_FALSE
TRUE GAL_TRUE
BOOL Gal_Boolean
OA_CHAR GAL_OA_CHAR
OA_SHORT GAL_OA_SHORT
OA_INT GAL_OA_INT
OA_FLOAT GAL_OA_FLOAT
OA_STRING GAL_OA_STRING
OA_DOUBLE GAL_OA_DOUBLE
oa_check_usage GalUtil_OACheckUsage
oa_print_usage GalUtil_OAPrintUsage
oa_extract GalUtil_OAExtract
oa_extract_asserting GalUtil_OAExtractAsserting
SLS_VERBOSE GAL_VERBOSE
sls_fatal GalUtil_Fatal
sls_warn GalUtil_Warn
sls_error GalUtil_Error
sls_print GalUtil_Print
sls_cprint GalUtil_CPrint
sls_pinfo1 GalUtil_PInfo1
sls_pinfo2 GalUtil_PInfo2
sls_cpinfo1 GalUtil_CPInfo1
sls_cpinfo2 GalUtil_CPInfo2
sls_debug1 GalUtil_Debug1
sls_debug2 GalUtil_Debug2
sls_assert GalUtil_Assert
sls_verbose_use_bw GalUtil_VerboseUseBW
sls_verbose_use_color GalUtil_VerboseUseColor


Step 4: Updating your header files

In GalaxyCommunicator 1.2, you needed a stubber to generate the headers "server.h" and "functions.h", which was not particularly portable across platforms because of the dependence on the power of GNU make. In GalaxyCommunicator 1.3, you had the option of using the new style of header declaration, which relies only on the C preprocessor; the old style was still available, but deprecated. In Galaxy Communicator 2.0, the old style is no longer supported, and you must upgrade.

Here's how the old style worked. For server declarations, the operations file contains the information about the server: server name, port, and operations.  This file was examined at server compile time to determine which operations would be called.  Based on the operations listed, a header file named "server.h" was automatically generated which mapped the name of each operation to the corresponding function in the server.  Port was needed to set the default port (unlike the program file, host was unnecessary). Here's a sample operations file from the double server:

The automatically generated header file "server.h" was added to exactly one of the source files in the server source code, and the operations file was declared in the Makefile. Finally, the SERVER_DATA directive instructed the stubber to generate headers for functions which took a second argument (actually the connection object).

For dialogue control headers, the file "functions.h" was automatically generated which contained both the dialogue control function prototypes and a function map.  The function prototypes were dictated by the operations listed in the dialogue control file rules.  The function map mapped the function name to the actual function call. The location of the dialogue control file was declared in the Makefile using DCTL_FILE, and USE_DCTL was set to 1.

Step 4a

First, generate the new headers. In version 2.0, MITRE provided a utility to help upgrading from the old to the new style. A detailed description of the new header structure for servers can be found here.; for dialogue control, look here.

Step 4b

Next, remove the OPERATIONS_FILE, SFUNC.H, SERVER_DATA, USE_DCTL, DCTL_FILE, and DFUNC.H declarations from your Makefile. Here's what they used to do:
 
Variable What it does Obligatory? Slot?
OPERATIONS_FILE The name of the operations file you need to define if you're using the old style of declaring server information. Defaults to galaxy/System/servers. no yes
SFUNC.H The name of the operations header file to generate, used for the old style of declaring server information. Defaults to server.h. no no
SERVER_DATA Value should be -server_data if you want to generate dispatch function signatures which contain an argument for the server structure. You should always use this if you're using the old style of declaring server information. no, but use it anyway if you're using the old style yes
USE_DCTL If the server uses the dialogue control mechanism, the value of this variable should be 1, using the old style of generating dialogue control headers. no yes
DCTL_FILE This variable specifies the dialogue control file for generating the dialogue function map, using the old style of generating dialogue control headers (the equivalent of server.h for the dialogue control mechanism). The default is galaxy/System/$(SERVER).dctl. no yes
DFUNC.H The name of the header file to generate for the dialogue function map, using the old style of generating dialogue control headers. Defaults to functions.h. no no


Step 5: Upgrading server access inside a dispatch function

In Galaxy Communicator 2.0, multiple connection support is built in, and as a result we have signficantly reorganized the connection management "under the hood" to provide a more consistent infrastructure. The distribution now makes a clear distinction between connections and servers, and introduces the notion of a call environment to embody the context of each call to a dispatch function (the administrative information that needs to be returned from that call, etc.). This object also provides access to the connection object (and to the server object). As a result, you will probably need to tease apart the different types of access to the connection infrastructure that you've made in your code.

In particular, the following important generalization applies:

We will elaborate on these distinctions below.

The first of these changes in the distribution has to do with the second argument of dispatch functions. In GalaxyCommunicator 1.3 and previous, the server_data argument of dispatch functions was not reliably a connection object. In 2.0, this argument is guaranteed to be a GalSS_Environment * (the call environment of the dispatch function). All functions which handled this unreliability have been deprecated. See the section on adding a server.

In your dispatch functions, make the following modifications:

Note that the order of the frame and connection arguments is reversed, and that the server-to-server subdialogues now return the type of the message return. More details are available in the server architecture documentation.

Note that parallel comments apply to the Python, Java and Common Lisp bindings.

In Python and Common Lisp, we've provided backward compatibility at the expense of a slight name misnomer; the Connection object is now actually a call environment object. If all you do is write frames to the Hub, access the server object and access the server object's output stream, these operations are all still transparently supported and your code should not need to change.

Note that the comments here apply only to dispatch functions. When you build a Communicator-compliant server, you have many opportunities to access the connection object for writing, etc. In addition to dispatch functions, you may set up another timed task whose callback function writes to the Hub (for instance, the MITRE stdin polling utility does this), or you might write a broker callback which writes to the Hub (as in the MITRE echo server). Even if you have access to a GalSS_Environment * object when you set up these callbacks, you cannot store this object away; as far as the programmer is concerned, the environment object does not persist past the scope of the dispatch function it is passed to. Instead, you must save away the connection object directly (accessible from the environment object via the GalSS_EnvComm() function. See the upgrade section on broker callbacks for a detailed comparison between 1.3 and 2.0 in such a case.


Step 6: Upgrading server access inside the reinitialize message

In GalaxyCommunicator 1.3 and previous, the reinitialize message behaved quite differently from other dispatch functions, in that the first frame it sent back to the Hub was interpreted as its return value, rather than the actual return from the dispatch function. This meant that if you wanted to send a new message from the reinitialize dispatch function, you had to write back a "dummy" frame first. Furthermore, at least one frame had to be sent, either as an explicit send or as the function return, because the Hub needed some response from the reinitialize message (even though it ignored it). These idiosyncracies have been eliminated. From the programmer's standpoint, the behavior of message dispatches in reinitialize is now identical to other dispatch functions. No return is required, and messages sent from inside reinitialize will be reliably interpreted as new messages, as they should. (Warning: reinitialize messages are still special "under the hood", and the reinitialize message can't yet be called anywhere except at startup. We will fix this problem in a subsequent release.)

Because the previous logic was obscure, and people may not want to take the time to reconstruct the proper logic, we have introduced the function GalSS_EnvForceReturn, which explicitly forces its frame argument to be treated as the dispatch function return. All messages sent to the Hub after a forced return are treated as new messages.This function can be used in any dispatch function, not just in reinitialize; most significantly, however, it can be used as a simple explicit substitute for the dummy message send. We illustrate the mapping with the reinitialize dispatch function from double.c.

Old:

Gal_Frame reinitialize(Gal_Frame frame, void *server_data)
{
  Gal_Frame new_f = Gal_MakeFrame("main", GAL_CLAUSE);

  /* Reply to reinitialize. */
  GalSS_WriteFrameToHub(frame, server_data, 0);
  /* New message. */
  Gal_SetProp(new_f, ":int", Gal_IntObject(InitialIncrement));
  return new_f;
}

Transparent substitution of GalSS_EnvForceReturn:
Gal_Frame reinitialize(Gal_Frame frame, void *server_data)
{
  Gal_Frame new_f = Gal_MakeFrame("main", GAL_CLAUSE);

  /* Reply to reinitialize. */
  GalSS_EnvForceReturn((GalSS_Environment *) server_data, f, 0);
  /* New message. */
  Gal_SetProp(new_f, ":int", Gal_IntObject(InitialIncrement));
  return new_f;
}

Corrected logic:
Gal_Frame reinitialize(Gal_Frame frame, void *server_data)
{
  Gal_Frame new_f = Gal_MakeFrame("main", GAL_CLAUSE);

  /* New message. */
  Gal_SetProp(new_f, ":int", Gal_IntObject(InitialIncrement));
  GalSS_EnvWriteFrame((GalSS_Environment *) server_data, new_f, 0);
  Gal_FreeFrame(new_f);
  return (Gal_Frame) NULL;
}

Note that parallel comments apply to the Python, Java and Common Lisp bindings.

In Python and Common Lisp, the required changes are exactly parallel. You may either transparently force a return, or reorganize the logic to match other dispatch functions.


Step 7: Upgrading server access from broker handlers

If you access server data or send messages to the Hub from broker callback functions, your task is slightly complicated than before, due to the new server/connection/environment paradigm. This example is drawn from the audio template demo.

Old:

static void synth_data_handler(GalIO_BrokerStruct *broker_struct, void *data,
          Gal_ObjectType data_type, int n_elements)
{
  Gal_Frame fr;

  switch (data_type) {
  case GAL_FRAME:
    printf("Answer is: `%s'\n",
    Gal_GetString((Gal_Frame) data, ":reply_string"));
    GalIO_BrokerDataDone(broker_struct);

    /* Now send playing is done */
    fr = Gal_MakeFrame("audio", GAL_CLAUSE);
    Gal_SetProp(fr, ":playing_has_ended", Gal_IntObject(1));
    GalSS_WriteFrameToHub(fr, (void *) NULL, 0);
    Gal_FreeFrame(fr);
    break;
  default:
    sls_warn("synth_data_handler: unexpected data type %s\n",
      Gal_ObjectTypeString(data_type));
  }
}

Gal_Frame handle_synth_data(Gal_Frame frame, void *server_data)
{
  char *host;
  int port;
  GalIO_BrokerStruct *b;

  host = (char *)Gal_GetValue(frame, ":synth_host", GAL_STRING);
  port = (int)Gal_GetValue(frame, ":synth_port", GAL_INT);

  if (host && port) {
    b = GalIO_BrokerDataInInit(host, port, frame,
                               synth_data_handler, server_data, 0);
    if (b) GalIO_SetBrokerActive(b);
  }
  return frame;
}

New:
static void synth_data_handler(GalIO_BrokerStruct *broker_struct, void *data,
                               Gal_ObjectType data_type, int n_elements)
{
  Gal_Frame fr;

  switch (data_type) {
  case GAL_FRAME:
    printf("Answer is: `%s'\n",
           Gal_GetString((Gal_Frame) data, ":reply_string"));
    GalIO_BrokerDataDone(broker_struct);

    /* Now send playing is done */
    fr = Gal_MakeFrame("audio", GAL_CLAUSE);
    Gal_SetProp(fr, ":playing_has_ended", Gal_IntObject(1));
    GalIO_CommWriteFrame((GalIO_CommStruct *) GalIO_GetBrokerCallerData(broker_struct), fr, 0);
    Gal_FreeFrame(fr);
    break;
  default:
    GalUtil_Warn("synth_data_handler: unexpected data type %s\n",
                 Gal_ObjectTypeString(data_type));
  }
}

Gal_Frame handle_synth_data(Gal_Frame frame, void *server_data)
{
  char *host;
  int port;
  GalIO_BrokerStruct *b;

  host = (char *)Gal_GetValue(frame, ":synth_host", GAL_STRING);
  port = (int)Gal_GetValue(frame, ":synth_port", GAL_INT);

  if (host && port) {
    b = GalIO_BrokerDataInInit(host, port, frame,
                               synth_data_handler,
                               GalSS_EnvComm((GalSS_Environment *) server_data), 0);
    if (b) GalIO_SetBrokerActive(b);
  }
  return frame;
}

Previously, the argument passed to the dispatch function was the server argument or NULL; now it is guaranteed to be a GalSS_Environment *. However, the environment object is reclaimed after the dispatch function is called, and as a result it can't be passed to the broker callback function to be stored. So the right thing to do is to store the actual connection object, accessed with the GalSS_EnvComm function, and send a message from the broker callback using GalIO_CommWriteFrame. If you want to access connection or server data, the lesson is the same: store the actual connection object and use GalIO_GetCommServerData and GalIO_GetCommData.

Note that parallel comments apply to the Python, Java and Common Lisp bindings.

In Python and Common Lisp, the broker data must be passed the connection object, but the dispatch function argument is now a call environment object instead. You must access the connection object from it. See the brokering examples in MITRE's audio example.


Step 8 (optional): Upgrading outgoing brokering creation

There are a number of reserved keys which various aspects of the Communicator library rely on for communication. We're trying to isolate those keys and protect them with functions when they are visible to the programmer. One instance of this is in setting up an outgoing brokering connection, in which the keys which store the broker port and the unique call ID must currently be set by the programmer to ensure a well-formed brokering connection. MITRE recommends the following upgrade. This upgrade affects outgoing brokering connections only. The example is taken from one of MITRE's audio examples, and is the same as the one used in the brokering documentation.

Old:

static Gal_Frame prepare_audio_frame(char *filename)
{
  /* .... */

  /* Now that we have the audio, we add a binary element. */
  /* These must be added to the broker frame BEFORE the
     broker object is initialized. */
  sprintf(host_pid, "%s:%d", GalIO_IPAddress(), (int) getpid());
  Gal_SetProp(f, ":call_id", Gal_StringObject(host_pid));
  b = GalIO_BrokerDataOutInit(3900, f, 0, 0);
  if (b && (Gal_GetInt(f, ":broker_port") > 0)) {
    Gal_SetProp(f, ":binary_host", Gal_StringObject(GalIO_IPAddress()));
    Gal_SetProp(f, ":binary_port",
                Gal_IntObject(Gal_GetInt(f, ":broker_port")));
    GalIO_BrokerWriteString(b, AUDIO_START);
    GalIO_BrokerWriteBinary(b, buf, total);
    GalIO_BrokerWriteString(b, AUDIO_END);
    GalIO_BrokerDataOutDone(b);
  }
  return f;
}

New:
static Gal_Frame prepare_audio_frame(char *filename)
{
  /* .... */

  /* Now that we have the audio, we add a binary element. */
  /* These must be added to the broker frame BEFORE the
     broker object is initialized. */
  sprintf(host_pid, "%s:%d", GalIO_IPAddress(), (int) getpid());
  GalIO_FrameSetBrokerCallID(f, host_pid);
  b = GalIO_BrokerDataOutInit(3900, f, 0, 0);
  if (b && (GalIO_FrameGetBrokerPort(f) > 0)) {
    Gal_SetProp(f, ":binary_host", Gal_StringObject(GalIO_IPAddress()));
    Gal_SetProp(f, ":binary_port",
                Gal_IntObject(GalIO_FrameGetBrokerPort(f)));
    GalIO_BrokerWriteString(b, AUDIO_START);
    GalIO_BrokerWriteBinary(b, buf, total);
    GalIO_BrokerWriteString(b, AUDIO_END);
    GalIO_BrokerDataOutDone(b);
  }
  return f;
}



Step 9 (advanced): Enabling signal handling

If you set signal handlers in your code anywhere, you should replace all calls to signal() and sigset() with calls to Gal_AddSignalHandler. This is in order to ensure that signals are handled correctly under threads. If you never intend to compile your servers with threads, you can omit this step.


Step 10 (advanced): Updating your own main loop

If you have written applications with their own main loops, you will have to make some extensive changes, once again due to the new server/connection/environment paradigm. The crucial steps are outlined here. We'll use the fd_double example.

Step 10a

First, you need to change the way your server is created.

Old:

int main(int argc, char **argv)
{
  GalaxyCallbackRecord *gcr = (GalaxyCallbackRecord *) NULL;

  gcr = (GalaxyCallbackRecord *) malloc(sizeof(GalaxyCallbackRecord));
  gcr->timer_cb = (TimerCallback *) NULL;
  gcr->server_sock = -1;
  gcr->client_sock = -1;
  gcr->l = SM_NewLooper();

  Gal_InitializeServerDefaults(ServerName, DefaultPort, SvrFunctionMap);
  gcr->gcomm = GalIO_ServerInit(Gal_GetServerPort(), 0,
                                GalSS_FrameHandler, (void *) gcr, -1);
  if (!gcr->gcomm) {
    fprintf(stderr, "Couldn't create a server\n");
    fflush(stderr);
    free(gcr->l);
    free(gcr);
    exit(1);
  }
  gcr->server_sock = GalIO_GetCommListenSocket(gcr->gcomm);
  SM_AddFDCallback(gcr->l, gcr->server_sock, DoubleServerHandler,
                   (void *) gcr);
  SM_Mainloop(gcr->l);
  exit(0);
}

New:
int main(int argc, char **argv)
{
  GalaxyCallbackRecord *gcr = (GalaxyCallbackRecord *) NULL;

  gcr = (GalaxyCallbackRecord *) malloc(sizeof(GalaxyCallbackRecord));
  gcr->timer_cb = (TimerCallback *) NULL;
  gcr->server_sock = -1;
  gcr->l = SM_NewLooper();

  gcr->gcomm = GalSS_InitializeServer(-1, 10, 0, 1, GAL_LOOP_EXTERNAL, 0, argc, argv);

  if (!gcr->gcomm) {
    fprintf(stderr, "Couldn't create a server\n");
    fflush(stderr);
    free(gcr->l);
    free(gcr);
    exit(1);
  }
  gcr->server_sock = GalIO_GetServerListenSocket(gcr->gcomm);
  SM_AddFDCallback(gcr->l, gcr->server_sock, DoubleServerHandler,
                   (void *) gcr);
  SM_Mainloop(gcr->l);
  exit(0);
}

Observe the following differences:

Step 10b

Next, you need to handle the way server callbacks are handled.

Old:

static void DoubleServerHandler(void *client_data)
{
  int status;
  GalaxyCallbackRecord *gcr = (GalaxyCallbackRecord *) client_data;

  status = GalIO_ServerHandler(gcr->gcomm);
  if ((status != -1) && (gcr->client_sock == -1)) {
    gcr->client_sock = GalIO_GetCommSocket(gcr->gcomm);
    SM_AddFDCallback(gcr->l, gcr->client_sock, DoubleConnectionHandler,
                     (void *) client_data);
  }
}

New: Observe the following differences: If you're using timers instead of file descriptor callbacks, the comparison is even more striking.

Old (from timer_double.c):

static void DoubleHandler(void *client_data)
{
  GalaxyCallbackRecord *gcr = (GalaxyCallbackRecord *) client_data;

  if (!gcr->server_connected) {
    switch (GalIO_ServerHandler(gcr->gcomm)) {
    case 1:
      gcr->server_connected = 1;
    }
  } else {
    switch (GalIO_ConnectionPoll(gcr->gcomm)) {
    case 1:
      /* Shut down the server */
      SM_RemoveTimerCallback(gcr->l, gcr->timer_cb);
      gcr->server_sock = -1;
      gcr->server_connected = 0;
      gcr->client_sock = -1;
      break;
    case -1:
      /* the connection is done */
      gcr->server_connected = 0;
      gcr->client_sock = -1;
      break;
    }
  }
}

New:
static void DoubleHandler(void *client_data)
{
  GalaxyCallbackRecord *gcr = (GalaxyCallbackRecord *) client_data;

  GalIO_ServerPoll(gcr->gcomm);
}

The new function GalIO_ServerPoll takes care of polling all the server's connections if the timed task loop is not enabled. You could also use this function in the file descriptor case, but it's less efficient.

Step 10c

Next, you need to change the way connection callbacks are handled.

Old:

static void DoubleConnectionHandler(void *client_data)
{
  GalaxyCallbackRecord *gcr = (GalaxyCallbackRecord *) client_data;

  /* GalIO_ConnectionPoll returns 1 when the server
     and client should be terminated, -1 when the
     client should be terminated. */
  switch (GalIO_ConnectionPoll(gcr->gcomm)) {
  case 1:
    /* Server disconnected */
    SM_RemoveFDCallback(gcr->l, gcr->server_sock);
    SM_RemoveFDCallback(gcr->l, gcr->client_sock);
    gcr->client_sock = -1;
    gcr->server_sock = -1;
    gcr->gcomm = (GalIO_CommStruct *) NULL;
    break;
  case -1:
    /* Client disconnected */
    SM_RemoveFDCallback(gcr->l, gcr->client_sock);
    gcr->client_sock = -1;
    break;
  }
}
 

New:
static void DoubleConnectionHandler(void *client_data)
{
  GalIO_CommStruct *new_conn = (GalIO_CommStruct *) client_data;
  GalaxyCallbackRecord *gcr = (GalaxyCallbackRecord *) GalIO_GetCommData(new_conn);
  int fd = GalIO_GetCommSocket(new_conn);

  /* GalIO_ConnectionPoll returns 1 or -1 when the client
     should be terminated. */
  switch (GalIO_ConnectionPoll(new_conn)) {
  case 1:
    /* Done, stop polling. */
  case -1:
    /* Error, stop polling. */
    SM_RemoveFDCallback(gcr->l, fd);
    break;
  default:
    break;
  }
}

Observe the following differences:

Step 11 (advanced): updating your use of stdin polling

If you use the MITRE stdin polling tool, you may want to modify it to reflect the fact that servers can accept more than one connection at a time. At the very least, you'd want to set the server maximum connections to 1; if you really want to be clean, you should modify your use of stdin polling to ensure that the poll is stored in the connection object, not in the server object. Although only one connection at a time is being accepted, this step ensures that the poll object is terminated at the appropriate points (that is, when connections die). This example is taken from the MITRE UI server.

Old:

void *_GalSS_init_server(GalIO_ServerStruct *s, int argc, char **argv)
{
  char *prompt;
  int i;
  char *prog_name;
  MGal_StdinPoll *poll_obj;

  if (!oa_check_usage(argc, argv, OAS, &i))
    exit(1);
  if (!oa_extract(argc, argv, OAS, "-prompt", OA_STRING, &prompt))
    prompt = DefaultPrompt;
  if (!oa_extract(argc, argv, OAS, "-prog_name", OA_STRING, &prog_name))
    prog_name = DefaultProgram;

  poll_obj = MGalSS_CreateStdinPoll(prompt,
                                    (void *) s, CreateTextFrame, 500, 0);
  MGal_SetStdinPollData(poll_obj, (void *) prog_name);

  return (void *) poll_obj;
}

Gal_Frame reinitialize(Gal_Frame f, void *server_data)
{
  if (Gal_GetObject(f, ":greeting")) {
    sls_print(-1, "[Greeting] %s\n", Gal_GetString(f, ":greeting"));
  }
  /* set up poll for stdin */
  MGal_ActivateStdinPoll((MGal_StdinPoll *) GalSS_GetServerData(server_data));
  return f;
}

New:
void *_GalSS_init_server(GalIO_ServerStruct *s, int argc, char **argv)
{
  int i;

  if (!GalUtil_OACheckUsage(argc, argv, OAS, &i))
    exit(1);
  if (!GalUtil_OAExtract(argc, argv, OAS, "-prompt", GAL_OA_STRING, &Prompt))
    Prompt = DefaultPrompt;
  if (!GalUtil_OAExtract(argc, argv, OAS, "-prog_name", GAL_OA_STRING, &ProgName))
    ProgName = DefaultProgram;
  GalIO_SetServerMaxConnections(s, 1);
  return (void *) NULL;
}

Gal_Frame reinitialize(Gal_Frame f, void *server_data)
{
  GalSS_Environment *env = (GalSS_Environment *) server_data;

  if (Gal_GetObject(f, ":greeting")) {
    GalUtil_Print(-1, "[Greeting] %s\n", Gal_GetString(f, ":greeting"));
  }

  GalSS_EnvSetCommData(env,
      (void *) MGalIO_CreateStdinPoll(Prompt, GalSS_EnvComm(env),
      CreateTextFrame, 500, 0), FreePoll);
  MGal_SetStdinPollData(GalSS_EnvGetCommData(env), (void *) ProgName);
  /* set up poll for stdin */
  MGal_ActivateStdinPoll((MGal_StdinPoll *) GalSS_EnvGetCommData(env));
  return f;
}

Observe the following differences:
License / Documentation home / Help and feedback
Last updated February 27, 2000