Go backward to Creating and modifying input structures.
Go up to Adding Input and Output Routines.

Output functions
----------------

An output function is called with two parameters: mode (an integer), and
outputs (a pointer to a chain of io_wme's).  An io_wme is just a structure
defined as follows:

typedef struct io_wme_struct {
  struct io_wme_struct *next;  /* points to next io_wme in the chain */
  Symbol *id;                  /* id, attribute, and value of the wme */
  Symbol *attr;
  Symbol *value;
} io_wme;

The chain of io_wme's passed to an output function is an (unordered) list of
all the working memory elements in the output structure.  (The last io_wme in
the list has its next field set to NULL (0).)  Mode takes one of three
values:


     
   * ADDED_OUTPUT_COMMAND: indicates that an output link has just been added
     to the top state.  In this case, outputs contains all the working memory
     elements in the output structure.
     
     
   * MODIFIED_OUTPUT_COMMAND: indicates that something in the transitive
     closure of an existing output link has changed.  In this case, outputs
     again contains all the working memory elements in the output structure
     (not just the modified ones).
     
     
   * REMOVED_OUTPUT_COMMAND: indicates that an output link has been removed
     from the top state.  In this case, outputs is a list with just one
     io_wme in it, for just the top-level output link wme that has been
     removed.

A typical output function will retrieve some key fields from the output
working memory elements, and use the retrieved values to take the appropriate
action.  One way to retrieve these values is for your code to walk down the
list of io_wme's and examine each one in turn.  Another way is to use
get_output_value(), a simple helping function for this.  Get_output_value()
takes three arguments: the outputs list, an identifier (Symbol *), and an
attribute (Symbol *).  It returns the value of that attribute on that
identifier.  (More precisely, it returns the value field of the first io_wme
in the list that matches the given id and attribute.  Either the id or
attribute argument can be given as a NULL pointer, rather than a pointer to a
symbol, in which case it is treated as a "don't care."  If none of the
working memory elements matches the id/attribute pair, the function returns a
NULL pointer.)

Note that Soar deallocates the outputs list after calling the output
function, so the output function is responsible for saving any necessary
information around for later.

The following example output function handles an output structure of the
form:

(S1 ^output-link I37)
(I37 ^command setup-command)

         or

(S1 ^output-link I37)
(I37 ^command change-fight-parameter)

It first retrieves the output link identifier (I37) from the output
structure, then retrieves the ^command name.  It takes one of several
possible actions, depending on what the command name is.

void my_output_function (int mode, io_wme *outputs) {
  Symbol *output_link_id, *command_name;
  Symbol *command_sym, *setup_command_sym,
         *change_flight_parameter_sym; 

  /* All we care about is new links, not changes to old ones */
  if (mode!=ADDED_OUTPUT_COMMAND) return;

  /* Fetch output_link_id (e.g. I37) so we can fetch values
     from it.  (top_state is a Soar-defined global variable.) */
  output_link_id = get_output_value (outputs, top_state, NIL);
  if (!output_link_id) return;

  /* Fetch "command" field of output link. */
  command_sym = get_io_sym_constant ("command");
  command_name = get_output_value (outputs, 
                                   output_link_id,
                                   command_sym);
  release_io_symbol(command_sym);
  if (!command_name) return;

  /* Branch on the command name. */             
  setup_command_sym = get_io_sym_constant ("setup-command");
  change_flight_parameter_sym =
    get_io_sym_constant ("change-fight-parameter");

  if (command_name == setup_command_sym) {
    /* Call setup command handler here */ }
  else if (command_name == change_flight_parameter_sym) {
    /* Call change-flight-parameter command hander here */ }
  else print_with_symbols ("\nI don't know command %y!!\n",
                           command_name);

  /* Clean up the symbols used. */
  release_io_symbol(setup_command_sym);
  release_io_symbol(change_flight_parameter_sym);
}

Note that there's more than one way to write the above output
function.  We could have setup_command_sym and
change_flight_parameter_sym be global variables---we would
initialize them by calling get_io_sym_constant() in our I/O
initialization routine.  This would save us the trouble of calling
get_io_sym_constant() and release_io_symbol() every time the
output function is called.  Another approach is to not have a
setup_command_sym at all---rather than compare
setup_command_sym to command_name, we could just examine the
command_name symbol directly, by looking at
command_name->common.symbol_type and possibly sc.name.