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

soar_core_api.c

Go to the documentation of this file.
00001 
00043 #include "soarkernel.h"
00044 #include <time.h>
00045 #include <stdlib.h>
00046 
00047 #include "soar_core_api.h"
00048 #include "soar_core_utils.h"
00049 #include "scheduler.h"
00050 
00051 extern char *soar_callback_names[];
00052 void soar_cTestCallback(soar_callback_agent the_agent, soar_callback_data data, soar_call_data call_data);
00053 
00054 /* *************************************************************************
00055  * *************************************************************************
00056  *   
00057  * SECTION 0:    ACCESSOR FUNCTIONS AND MACROS
00058  *
00059  *               - Agent State
00060  *
00061  * *************************************************************************
00062  * *************************************************************************
00063  */
00064 
00065 /* Will be renamed to soar_cSetSysparam */
00066 void set_sysparam(int param_number, long new_value)
00067 {
00068 
00069     if ((param_number < 0) || (param_number > HIGHEST_SYSPARAM_NUMBER)) {
00070         print("Internal error: tried to set bad sysparam #: %d\n", param_number);
00071         return;
00072     }
00073     current_agent(sysparams)[param_number] = new_value;
00074 
00075     soar_invoke_callbacks(soar_agent, SYSTEM_PARAMETER_CHANGED_CALLBACK, (soar_call_data) param_number);
00076 
00077 }
00078 
00079 /* *************************************************************************
00080  * *************************************************************************
00081  *   
00082  * SECTION 1:    CRITICAL FUNCTIONS
00083  *
00084  *               - (Re)Initializing Soar
00085  *                   - Creating Agents
00086  *               - Destroying Agents
00087  *               - Starting and Stopping Agents
00088  *
00089  * *************************************************************************
00090  * *************************************************************************
00091  */
00092 
00093 extern int soar_agent_ids[];
00094 extern int agent_counter;
00095 extern soar_global_callback_array soar_global_callbacks;
00096 
00097 extern void gds_invalid_so_remove_goal(wme * w);
00098 
00099 #if defined(WIN32)
00100 #include <stdio.h>
00101 #include <stdlib.h>
00102 #include <string.h>
00103 
00104 #define popen(command, mode) _popen((command), (mode))
00105 #define pclose(stream) _pclose(stream)
00106 #endif
00107 
00108 /*
00109  *----------------------------------------------------------------------
00110  *
00111  * soar_cInitializeSoar
00112  *
00113  *     Initialize Soar for the very first time. 
00114  *     (Before any agents are created)
00115  *
00116  *----------------------------------------------------------------------
00117  */
00118 
00119 #define SOAR_CINITIALIZESOAR_BUFFER_SIZE 1000
00120 void soar_cInitializeSoar(void)
00121 {
00122     char buffer[SOAR_CINITIALIZESOAR_BUFFER_SIZE];
00123     int i;
00124 
00125 #if MICRO_VERSION_NUMBER > 0
00126     snprintf(buffer, SOAR_CINITIALIZESOAR_BUFFER_SIZE,
00127              "%d.%d.%d", MAJOR_VERSION_NUMBER, MINOR_VERSION_NUMBER, MICRO_VERSION_NUMBER);
00128     buffer[SOAR_CINITIALIZESOAR_BUFFER_SIZE - 1] = 0;   /* snprintf doesn't set last char to null if output is truncated */
00129 #else
00130     snprintf(buffer, SOAR_CINITIALIZESOAR_BUFFER_SIZE, "%d.%d", MAJOR_VERSION_NUMBER, MINOR_VERSION_NUMBER);
00131     buffer[SOAR_CINITIALIZESOAR_BUFFER_SIZE - 1] = 0;   /* snprintf doesn't set last char to null if output is truncated */
00132 #endif
00133 
00134     soar_version_string = savestring(buffer);
00135 
00136     /*  RCHONG and REW added following to soar_version_string.
00137      *  KJC leaving it out for now, since Tcl Pkg mechanism
00138      *  relies on soar_version_string to load right package.
00139      *  Will add it in interface level with other options.
00140      */
00141 
00142     /* 
00143      *   if (current_agent(operand2_mode) == TRUE)
00144      *      sprintf(buffer,"%s-%s", OPERAND_MODE_NAME);
00145      */
00146 /* REW: end   09.15.96 */
00147 
00148     /* --- set the random number generator seed to a "random" value --- */
00149     sys_srandom(time(NULL));
00150 
00151     setup_signal_handling();
00152 
00153     /* SW 081299 */
00154     /* No assigned agent ids */
00155     for (i = 0; i < MAX_SIMULTANEOUS_AGENTS; i++)
00156         soar_agent_ids[i] = UNTOUCHED;
00157 
00158     soar_init_global_callbacks();
00159 }
00160 
00161 /*
00162  *----------------------------------------------------------------------
00163  *
00164  * soar_cReInitSoar --
00165  *
00166  *      ReInitialize Soar by clearing the working memory of all agents
00167  *      and preparing them for a "new" execution
00168  *
00169  *----------------------------------------------------------------------
00170  */
00171 int soar_cReInitSoar(void)
00172 {
00173 
00174     /* kjh (CUSP-B4) begin */
00175     long cur_TRACE_CONTEXT_DECISIONS_SYSPARAM;
00176     long cur_TRACE_PHASES_SYSPARAM;
00177     long cur_TRACE_FIRINGS_OF_DEFAULT_PRODS_SYSPARAM;
00178     long cur_TRACE_FIRINGS_OF_USER_PRODS_SYSPARAM;
00179     long cur_TRACE_FIRINGS_WME_TRACE_TYPE_SYSPARAM;
00180     long cur_TRACE_FIRINGS_PREFERENCES_SYSPARAM;
00181     long cur_TRACE_WM_CHANGES_SYSPARAM;
00182     /* kjh (CUSP-B4) end */
00183 
00184     current_agent(did_PE) = FALSE;      /* RCHONG:  10.11 */
00185 
00186     soar_invoke_callbacks(soar_agent, BEFORE_INIT_SOAR_CALLBACK, (soar_call_data) NULL);
00187 
00188     /* kjh (CUSP-B4) begin */
00189     /* Stash trace state: */
00190     cur_TRACE_CONTEXT_DECISIONS_SYSPARAM = current_agent(sysparams)[TRACE_CONTEXT_DECISIONS_SYSPARAM];
00191     cur_TRACE_PHASES_SYSPARAM = current_agent(sysparams)[TRACE_PHASES_SYSPARAM];
00192     cur_TRACE_FIRINGS_OF_DEFAULT_PRODS_SYSPARAM = current_agent(sysparams)[TRACE_FIRINGS_OF_DEFAULT_PRODS_SYSPARAM];
00193     cur_TRACE_FIRINGS_OF_USER_PRODS_SYSPARAM = current_agent(sysparams)[TRACE_FIRINGS_OF_USER_PRODS_SYSPARAM];
00194     cur_TRACE_FIRINGS_WME_TRACE_TYPE_SYSPARAM = current_agent(sysparams)[TRACE_FIRINGS_WME_TRACE_TYPE_SYSPARAM];
00195     cur_TRACE_FIRINGS_PREFERENCES_SYSPARAM = current_agent(sysparams)[TRACE_FIRINGS_PREFERENCES_SYSPARAM];
00196     cur_TRACE_WM_CHANGES_SYSPARAM = current_agent(sysparams)[TRACE_WM_CHANGES_SYSPARAM];
00197 
00198     /* Temporarily disable tracing: */
00199     set_sysparam(TRACE_CONTEXT_DECISIONS_SYSPARAM, FALSE);
00200     set_sysparam(TRACE_PHASES_SYSPARAM, FALSE);
00201     set_sysparam(TRACE_FIRINGS_OF_DEFAULT_PRODS_SYSPARAM, FALSE);
00202     set_sysparam(TRACE_FIRINGS_OF_USER_PRODS_SYSPARAM, FALSE);
00203     set_sysparam(TRACE_FIRINGS_WME_TRACE_TYPE_SYSPARAM, NONE_WME_TRACE);
00204     set_sysparam(TRACE_FIRINGS_PREFERENCES_SYSPARAM, FALSE);
00205     set_sysparam(TRACE_WM_CHANGES_SYSPARAM, FALSE);
00206     /* kjh (CUSP-B4) end */
00207 
00208     clear_goal_stack();
00209 
00210 #ifndef SOAR_8_ONLY
00211     if (current_agent(operand2_mode) == TRUE) {
00212 #endif
00213 
00214         /* Signal that everything should be retracted */
00215         current_agent(active_level) = 0;
00216 
00217         current_agent(FIRING_TYPE) = IE_PRODS;
00218         do_preference_phase();  /* allow all i-instantiations to retract */
00219 
00220         /* REW: begin  09.22.97 */
00221 
00222         /* In Operand2,  any retractions, regardless of i-instantitations or
00223            o-instantitations, are retracted at the saem time (in an IE_PRODS
00224            phase).  So one call to the preference phase should be sufficient. */
00225 
00226         /* DELETED code to set FIRING_TYPE to PE and call preference phase. */
00227 
00228         /* REW: end    09.22.97 */
00229 #ifndef SOAR_8_ONLY
00230     }
00231 
00232     /* REW: end  09.15.96 */
00233     else
00234         do_preference_phase();  /* allow all instantiations to retract */
00235 #endif
00236 
00237     reset_explain();
00238     reset_id_counters();
00239     reset_wme_timetags();
00240     reset_statistics();
00241     current_agent(system_halted) = FALSE;
00242     current_agent(go_number) = 1;
00243     current_agent(go_type) = GO_DECISION;
00244 
00245     /* kjh (CUSP-B4) begin */
00246     /* Restore trace state: */
00247     set_sysparam(TRACE_CONTEXT_DECISIONS_SYSPARAM, cur_TRACE_CONTEXT_DECISIONS_SYSPARAM);
00248     set_sysparam(TRACE_PHASES_SYSPARAM, cur_TRACE_PHASES_SYSPARAM);
00249     set_sysparam(TRACE_FIRINGS_OF_DEFAULT_PRODS_SYSPARAM, cur_TRACE_FIRINGS_OF_DEFAULT_PRODS_SYSPARAM);
00250     set_sysparam(TRACE_FIRINGS_OF_USER_PRODS_SYSPARAM, cur_TRACE_FIRINGS_OF_USER_PRODS_SYSPARAM);
00251     set_sysparam(TRACE_FIRINGS_WME_TRACE_TYPE_SYSPARAM, cur_TRACE_FIRINGS_WME_TRACE_TYPE_SYSPARAM);
00252     set_sysparam(TRACE_FIRINGS_PREFERENCES_SYSPARAM, cur_TRACE_FIRINGS_PREFERENCES_SYSPARAM);
00253     set_sysparam(TRACE_WM_CHANGES_SYSPARAM, cur_TRACE_WM_CHANGES_SYSPARAM);
00254     /* kjh (CUSP-B4) end */
00255 
00256     soar_invoke_callbacks(soar_agent, AFTER_INIT_SOAR_CALLBACK, (soar_call_data) NULL);
00257 
00258     current_agent(input_cycle_flag) = TRUE;     /* reinitialize flag  AGR REW1 */
00259 
00260     /* REW: begin 09.15.96 */
00261 #ifndef SOAR_8_ONLY
00262     if (current_agent(operand2_mode) == TRUE) {
00263 #endif
00264 
00265         current_agent(FIRING_TYPE) = IE_PRODS;  /* KJC 10.05.98 was PE */
00266         current_agent(current_phase) = INPUT_PHASE;
00267         current_agent(did_PE) = FALSE;
00268 #ifndef SOAR_8_ONLY
00269     }
00270 #endif
00271     /* REW: end 09.15.96 */
00272 
00273 #ifdef WARN_IF_TIMERS_REPORT_ZERO
00274     current_agent(warn_on_zero_timers) = TRUE;
00275 #endif
00276 
00277     return 0;
00278 }
00279 
00280 /*
00281  *----------------------------------------------------------------------
00282  *
00283  * soar_cCreateAgent --
00284  *
00285  *      Create a new soar agent with the specified name.
00286  *
00287  *----------------------------------------------------------------------
00288  */
00289 
00290 void soar_cCreateAgent(const char *agent_name)
00291 {
00292 
00293     if (soar_exists_global_callback(GLB_CREATE_AGENT)) {
00294         soar_invoke_global_callbacks(NULL, GLB_CREATE_AGENT, (soar_call_data) agent_name);
00295     } else {
00296         soar_default_create_agent_procedure(agent_name);
00297     }
00298 
00299 }
00300 
00301 /*
00302  *----------------------------------------------------------------------
00303  *
00304  * soar_cRun --
00305  *
00306  *      Run the current agent, or all agents for a specified
00307  *      period ...
00308  *
00309  *----------------------------------------------------------------------
00310  */
00311 int soar_cRun(long n, bool allAgents, enum go_type_enum type, enum soar_apiSlotType slot)
00312 {
00313 
00314     int levels_up;
00315     Symbol *attribute, *goal;
00316     cons *c;
00317 
00318     if (type != GO_SLOT && slot != NO_SLOT)
00319         return -1;
00320 
00321     if (n < -1)
00322         n = -1;
00323 
00324     switch (type) {
00325 
00326     case GO_PHASE:
00327         run_for_n_phases(n);
00328         break;
00329     case GO_ELABORATION:
00330         run_for_n_elaboration_cycles(n);
00331         break;
00332     case GO_DECISION:
00333         run_for_n_decision_cycles(n);
00334         break;
00335     case GO_STATE:
00336         run_for_n_selections_of_slot(n, soar_agent->state_symbol);
00337         break;
00338     case GO_OPERATOR:
00339         run_for_n_selections_of_slot(n, soar_agent->operator_symbol);
00340         break;
00341 
00342     case GO_OUTPUT:
00343         run_for_n_modifications_of_output(n);
00344         break;
00345 
00346     case GO_SLOT:
00347         switch (slot) {
00348 
00349         case STATE_SLOT:
00350             levels_up = 0;
00351             attribute = current_agent(state_symbol);
00352             break;
00353         case OPERATOR_SLOT:
00354             levels_up = 0;
00355             attribute = current_agent(operator_symbol);
00356             break;
00357         case SUPERSTATE_SLOT:
00358             levels_up = 1;
00359             attribute = current_agent(state_symbol);
00360             break;
00361         case SUPEROPERATOR_SLOT:
00362             levels_up = 1;
00363             attribute = current_agent(operator_symbol);
00364             break;
00365         case SUPERSUPERSTATE_SLOT:
00366             levels_up = 2;
00367             attribute = current_agent(state_symbol);
00368             break;
00369         case SUPERSUPEROPERATOR_SLOT:
00370             levels_up = 2;
00371             attribute = current_agent(operator_symbol);
00372             break;
00373 
00374         default:
00375             return -2;
00376             break;
00377 
00378         }                       /* End of switch (slot) */
00379 
00380         goal = current_agent(bottom_goal);
00381         while (goal && levels_up) {
00382             goal = goal->id.higher_goal;
00383             levels_up--;
00384         }
00385 
00386         if (!goal)
00387             return -3;
00388 
00389         run_all_agents(n, GO_SLOT, attribute, goal->id.level);
00390 
00391         break;
00392 
00393     }                           /* End of switch type */
00394 
00395     if (allAgents) {
00396         for (c = all_soar_agents; c != NIL; c = c->rest) {
00397             if (((agent *) c->first)->system_halted)
00398                 return -4;
00399         }
00400     } else {
00401         if (current_agent(system_halted))
00402             return -4;
00403     }
00404     return 0;
00405 }
00406 
00407 /*
00408  *----------------------------------------------------------------------
00409  *
00410  * soar_cStopAllAgents()
00411  *
00412  *     Stops all agents
00413  *
00414  *----------------------------------------------------------------------
00415  */
00416 void soar_cStopAllAgents(void)
00417 {
00418     control_c_handler(0);
00419 }
00420 
00421 /*
00422  *----------------------------------------------------------------------
00423  *
00424  * soar_cStopCurrentAgent()
00425  *
00426  *     Stops the current agent
00427  *
00428  *----------------------------------------------------------------------
00429  */
00430 void soar_cStopCurrentAgent(const char *reason)
00431 {
00432     current_agent(stop_soar) = TRUE;
00433     current_agent(reason_for_stopping) = reason;
00434 
00435 }
00436 
00437 /* 
00438  *----------------------------------------------------------------------
00439  *
00440  * soar_cDestroyAgentByName --
00441  *
00442  *     Destroy an agent, given its name
00443  *
00444  *     (calls the common DestroyAgent ancestor: 
00445  *         soar_cDestroyAgentByAddress)
00446  *
00447  *----------------------------------------------------------------------
00448  */
00449 int soar_cDestroyAgentByName(const char *name)
00450 {
00451     cons *c;
00452     int name_count = 0;
00453     psoar_agent *delete_me = NULL;
00454 
00455     for (c = all_soar_agents; c != NIL; c = c->rest) {
00456         if (string_match(name, ((agent *) c->first)->name)) {
00457             name_count++;
00458             delete_me = (psoar_agent) c->first;
00459         }
00460     }
00461     if (name_count > 1)
00462         return -1;
00463     if (name_count == 0)
00464         return -2;
00465     soar_cDestroyAgentByAddress(delete_me);
00466 
00467     return 0;
00468 }
00469 
00470 /* 
00471  *----------------------------------------------------------------------
00472  *
00473  * soar_cDestroyAllAgentsWithName --
00474  *
00475  *     Destroy all agents with a given name
00476  *
00477  *     (calls the common DestroyAgent ancestor: 
00478  *         soar_cDestroyAgentByAddress)
00479  *
00480  *----------------------------------------------------------------------
00481  */
00482 int soar_cDestroyAllAgentsWithName(char *name)
00483 {
00484     cons *c;
00485     int count;
00486 
00487     count = 0;
00488     for (c = all_soar_agents; c != NIL; c = c->rest) {
00489         if (string_match(name, ((agent *) c->first)->name)) {
00490             count++;
00491             soar_cDestroyAgentByAddress((psoar_agent) c->first);
00492 
00493         }
00494     }
00495     if (count == 0)
00496         return -1;
00497     return 0;
00498 }
00499 
00500 /*
00501  *----------------------------------------------------------------------
00502  *
00503  * soar_cDestroyAgentByAddress --
00504  *
00505  *     Destroy an agent, given a pointer to it.
00506  *
00507  *     (This function is the common ancestor 
00508  *      of all other DestroyAgent functions)
00509  *
00510  *----------------------------------------------------------------------
00511  */
00512 void soar_cDestroyAgentByAddress(psoar_agent delete_agent)
00513 {
00514 
00515     if (soar_exists_global_callback(GLB_DESTROY_AGENT)) {
00516         soar_invoke_global_callbacks(delete_agent, GLB_DESTROY_AGENT, (soar_call_data) delete_agent);
00517     } else {
00518         soar_default_destroy_agent_procedure(delete_agent);
00519     }
00520 }
00521 
00522 /* 
00523  *----------------------------------------------------------------------
00524  *
00525  * soar_cDestroyAgentById --
00526  *
00527  *     Destroy an agent, given its unique id
00528  *
00529  *     (calls the common DestroyAgent ancestor: 
00530  *         soar_cDestroyAgentByAddress)
00531  *
00532  *----------------------------------------------------------------------
00533  */
00534 int soar_cDestroyAgentById(int agent_id)
00535 {
00536     cons *c;
00537 
00538     for (c = all_soar_agents; c != NIL; c = c->rest) {
00539         if (agent_id == ((agent *) c->first)->id) {
00540             soar_cDestroyAgentByAddress((psoar_agent) c->first);
00541             return 0;
00542         }
00543     }
00544 
00545     /* Didn't find agent id */
00546     return -1;
00547 }
00548 
00549 /*
00550  *----------------------------------------------------------------------
00551  *
00552  * soar_cQuit --
00553  *
00554  *     stop the log files, and quit
00555  *
00556  *----------------------------------------------------------------------
00557  */
00558 void soar_cQuit(void)
00559 {
00560 
00561     /* If there aren't any agents, then there's nothing to do */
00562     if (!soar_agent)
00563         return;
00564 
00565     just_before_exit_soar();
00566 
00567     /* Soar-Bugs #58, TMH */
00568     while (soar_exists_callback(soar_agent, LOG_CALLBACK)) {
00569 
00570         soar_invoke_first_callback(soar_agent, LOG_CALLBACK, "\n**** quit cmd issued ****\n");
00571         soar_cPopCallback(soar_agent, LOG_CALLBACK);
00572     }
00573 #ifdef USE_AGENT_DBG_FILE
00574     fclose(current_agent(dbgFile));
00575 #endif
00576 
00577 }
00578 
00579 /* *************************************************************************
00580  * *************************************************************************
00581  *   
00582  * SECTION 2:    MODIFYING AGENT MEMORY
00583  *
00584  *               - Production Memory
00585  *               - Working Memory
00586  *
00587  * *************************************************************************
00588  * *************************************************************************
00589  */
00590 
00591 /*
00592  *----------------------------------------------------------------------
00593  *
00594  * soar_cLoadReteNet --
00595  *
00596  *     load a Rete Network into the agent from a specified file
00597  *
00598  *----------------------------------------------------------------------
00599  */
00600 int soar_cLoadReteNet(const char *filename)
00601 {
00602 
00603     char pipe_command[] = "zcat ";
00604     bool using_compression_filter;
00605     char *append_loc, *command_line;
00606     FILE *f;
00607     bool result;
00608     int i;
00609 
00610     if (!filename) {
00611         print("Internal error: No file name specified.\n");
00612         return SOAR_ERROR;
00613     }
00614 
00615     /* --- check for empty system --- */
00616     if (current_agent(all_wmes_in_rete)) {
00617         print("Internal error: Can't load RETE in non-empty system.  Restart Soar first.\n");
00618         return SOAR_ERROR;
00619     }
00620 
00621     for (i = 0; i < NUM_PRODUCTION_TYPES; i++)
00622         if (current_agent(num_productions_of_type)[i]) {
00623             print("Internal error: Can't load RETE in non-empty system.  Restart Soar first.\n");
00624             return SOAR_ERROR;
00625         }
00626 
00627 #if !defined(MACINTOSH)         /* Mac doesn't have pipes */
00628     if ((!(strcmp((char *) (filename + strlen(filename) - 2), ".Z")))
00629         || (!(strcmp((char *) (filename + strlen(filename) - 2), ".z")))) {
00630 
00631         /* The popen can succeed if given an non-existant file   
00632            creating an unusable pipe.  So we check to see if the 
00633            file exists first, on a load action.                  */
00634 
00635         f = fopen(filename, "rb");
00636 
00637         if (!f) {
00638             /* --- error when opening the file --- */
00639             print("Internal error: Error opening file.\n");
00640             return SOAR_ERROR;
00641 
00642         } else {
00643             fclose(f);
00644         }
00645 
00646         command_line = allocate_memory(strlen(pipe_command) + strlen(filename) + 1, STRING_MEM_USAGE);
00647 
00648         strcpy(command_line, pipe_command);     /* this is relatively safe since the memory is allocated on the previous line */
00649 
00650         append_loc = command_line;
00651         while (*append_loc)
00652             append_loc++;
00653 
00654         strcpy(append_loc, filename);   /* this is relatively safe since sufficient memory is allocated earlier */
00655 
00656         f = (FILE *) popen(command_line, "rb");
00657         free_memory(command_line, STRING_MEM_USAGE);
00658 
00659         using_compression_filter = TRUE;
00660     } else
00661 #endif                          /* !MACINTOSH */
00662     {
00663 
00664         f = fopen(filename, "rb");
00665         using_compression_filter = FALSE;
00666     }
00667 
00668     if (!f) {
00669         /* --- error when opening the pipe or file --- */
00670         print("Internal error: error opening file.\n");
00671         return SOAR_ERROR;
00672 
00673     }
00674 
00675     result = load_rete_net(f);
00676 
00677 #if !defined(MACINTOSH)
00678     if (using_compression_filter == TRUE) {
00679         pclose(f);
00680     } else
00681 #endif                          /* !MACINTOSH */
00682     {
00683         fclose(f);
00684     }
00685 
00686     return SOAR_OK;
00687 }
00688 
00689 /*
00690  *----------------------------------------------------------------------
00691  *
00692  * soar_cSaveReteNet --
00693  *
00694  *     save a Rete Network into the agent from a specified file
00695  *
00696  *----------------------------------------------------------------------
00697  */
00698 
00699 int soar_cSaveReteNet(const char *filename)
00700 {
00701 
00702     char *command_line;
00703     char pipe_command[] = "compress > ";
00704     FILE *f;
00705     bool using_compression_filter = FALSE;
00706     char *append_loc;
00707 
00708     if (current_agent(all_productions_of_type)[JUSTIFICATION_PRODUCTION_TYPE]) {
00709         print("Internal error: can't save rete with justifications present.\n");
00710         return SOAR_ERROR;
00711     }
00712 
00713 #if !defined(MACINTOSH)         /* Mac doesn't have pipes */
00714     if ((!(strcmp((char *) (filename + strlen(filename) - 2), ".Z")))
00715         || (!(strcmp((char *) (filename + strlen(filename) - 2), ".z")))) {
00716 
00717         command_line = allocate_memory(strlen(pipe_command) + strlen(filename) + 1, STRING_MEM_USAGE);
00718 
00719         strcpy(command_line, pipe_command);     /* this is relatively safe since the memory is allocated on the previous line */
00720 
00721         append_loc = command_line;
00722         while (*append_loc)
00723             append_loc++;
00724 
00725         strcpy(append_loc, filename);   /* this is relatively safe since the memory is allocated earlier */
00726 
00727         f = (FILE *) popen(command_line, "wb");
00728         free_memory(command_line, STRING_MEM_USAGE);
00729 
00730         using_compression_filter = TRUE;
00731 
00732     } else
00733 #endif                          /* !MACINTOSH */
00734     {
00735 
00736         f = fopen(filename, "wb");
00737         using_compression_filter = FALSE;
00738     }
00739 
00740     if (!f) {
00741         /* --- error when opening the pipe or file --- */
00742         print("Internal error: error opening file.\n");
00743         return SOAR_ERROR;
00744     }
00745 
00746     save_rete_net(f);
00747 
00748 #if !defined(MACINTOSH)
00749     if (using_compression_filter == TRUE) {
00750         pclose(f);
00751     } else
00752 #endif                          /* !MACINTOSH */
00753     {
00754         fclose(f);
00755     }
00756 
00757     return SOAR_OK;
00758 }
00759 
00760 /*
00761  *----------------------------------------------------------------------
00762  *
00763  * soar_cAddWme
00764  *
00765  *     Remove a working memory element, given its timetag
00766  *
00767  *----------------------------------------------------------------------
00768  */
00769 /*unsigned long soar_cAddWme( const char *szId, const char *szAttr, const char *szValue, */
00770 long soar_cAddWme(const char *szId, const char *szAttr, const char *szValue,
00771                   bool acceptable_preference, psoar_wme * new_wme)
00772 {
00773 
00774     Symbol *id, *attr, *value;
00775     wme *w;
00776 
00777     /* --- get id --- */
00778     if (read_id_or_context_var_from_string(szId, &id) == SOAR_ERROR)
00779         return -1;
00780 
00781     /* --- get optional '^', if present --- */
00782 
00783     if (*szAttr == '^')
00784         szAttr++;
00785 
00786     /* --- get attribute or '*' --- */
00787     if (string_match("*", szAttr) == TRUE) {
00788 #ifdef USE_AGENT_DBG_FILE
00789         fprintf(current_agent(dbgFile), "'%s' matches '*'\n", szAttr);
00790 #endif
00791 
00792         attr = make_new_identifier('I', id->id.level);
00793     } else {
00794         get_lexeme_from_string(szAttr);
00795 
00796         switch (current_agent(lexeme).type) {
00797         case SYM_CONSTANT_LEXEME:
00798             attr = make_sym_constant(current_agent(lexeme).string);
00799             break;
00800         case INT_CONSTANT_LEXEME:
00801             attr = make_int_constant(current_agent(lexeme).int_val);
00802             break;
00803         case FLOAT_CONSTANT_LEXEME:
00804             attr = make_float_constant(current_agent(lexeme).float_val);
00805             break;
00806         case IDENTIFIER_LEXEME:
00807         case VARIABLE_LEXEME:
00808             attr = read_identifier_or_context_variable();
00809             if (!attr) {
00810                 return -2;
00811             }
00812             symbol_add_ref(attr);
00813             break;
00814         default:
00815             return -2;
00816         }
00817     }
00818 
00819     /* --- get value or '*' --- */
00820 
00821     if (string_match("*", szValue) == TRUE) {
00822         value = make_new_identifier('I', id->id.level);
00823     } else {
00824         get_lexeme_from_string(szValue);
00825         switch (current_agent(lexeme).type) {
00826         case SYM_CONSTANT_LEXEME:
00827             value = make_sym_constant(current_agent(lexeme).string);
00828             break;
00829         case INT_CONSTANT_LEXEME:
00830             value = make_int_constant(current_agent(lexeme).int_val);
00831             break;
00832         case FLOAT_CONSTANT_LEXEME:
00833             value = make_float_constant(current_agent(lexeme).float_val);
00834             break;
00835         case IDENTIFIER_LEXEME:
00836         case VARIABLE_LEXEME:
00837             value = read_identifier_or_context_variable();
00838             if (!value) {
00839                 symbol_remove_ref(attr);
00840                 return -3;
00841             }
00842             symbol_add_ref(value);
00843             break;
00844         default:
00845             symbol_remove_ref(attr);
00846             return -3;
00847         }
00848     }
00849 
00850     /* --- now create and add the wme --- */
00851     w = make_wme(id, attr, value, acceptable_preference);
00852 
00853     symbol_remove_ref(w->attr);
00854     symbol_remove_ref(w->value);
00855     insert_at_head_of_dll(w->id->id.input_wmes, w, next, prev);
00856     add_wme_to_wm(w);
00857 
00858 #ifdef USE_CAPTURE_REPLAY
00859     /* KJC 11/99 begin: */
00860     /* if input capturing is enabled, save any input wmes to capture file */
00861     if (current_agent(capture_fileID) && (current_agent(current_phase) == INPUT_PHASE)) {
00862 
00863         soarapi_wme sapi_wme;
00864 
00865         /* Dont copy, since capture_input_wme is just going to print
00866          * the contents of the structure into a file... 
00867          */
00868         sapi_wme.id = szId;
00869         sapi_wme.attr = szAttr;
00870         sapi_wme.value = szValue;
00871         sapi_wme.timetag = w->timetag;
00872 
00873         capture_input_wme(ADD_WME, &sapi_wme, w);
00874     }
00875     /* KJC 11/99 end */
00876 
00877 #endif                          /* USE_CAPTURE_REPLAY */
00878 
00879     /* REW: begin 28.07.96 */
00880     /* OK.  This is an ugly hack.  Basically we want to keep track of kernel
00881        time and callback time.  add-wme is called from either a callback
00882        (for input routines) or from the command line (or someplace else?).
00883        Here, I'm just assuming that we'll normally call add-wme from an
00884        input routine so I turn off the input_function_timer and turn on
00885        the kernel timers before the call to the low-level function:
00886        do_buffered_wm_and_ownership_changes.
00887 
00888        This assumption is problematic because anytime add-wme is called 
00889        from some place other than the input function, there is a potential
00890        to get some erroneous (if start_kernel_tv wasn't set for the 
00891        input function) or just bad (if start_kernel_tv isn't defined)
00892        timing data.   The real problem is that this very high-level 
00893        routine is going deep into the kernel.  We can either ignore
00894        this and just call the time spent doing wm changes here time
00895        spent outside the kernel or we can try to do the accounting,
00896        what this hack is a first-attempt at doing.  
00897 
00898        However, my testing turned up no problems -- I was able to add
00899        and remove WMEs without messing up the timers.  So it`s a 
00900        hack that seems to work.  For now.  (there is a plan to 
00901        add routines for specifically adding and deleting input
00902        WMEs which should help clear up this isse)               REW */
00903 
00904     /* REW: end 28.07.96 */
00905 
00906 #ifndef NO_TIMING_STUFF
00907     if (current_agent(current_phase) == INPUT_PHASE) {
00908         /* Stop input_function_cpu_time timer.  Restart kernel and phase timers */
00909         stop_timer(&current_agent(start_kernel_tv), &current_agent(input_function_cpu_time));
00910         start_timer(&current_agent(start_kernel_tv));
00911 
00912 #ifndef KERNEL_TIME_ONLY
00913         start_timer(&current_agent(start_phase_tv));
00914 #endif
00915     }
00916 #endif
00917 /* REW: end 28.07.96 */
00918 
00919     /* note: 
00920      * I don't completely understand this:
00921      * The deal seems to be that when NO_TOP_LEVEL_REFS is used, wmes on the i/o
00922      * link (obviously) have fewer references than thy would otherwise.
00923      * Although calling this here (in soar_cAddWme) doesn't seem to matter
00924      * one way or the other, calling it in soar_cRemoveWme really leads to 
00925      * problems.  What happens is that the i/o wme is removed prior to 
00926      * fully figuring out the match set.  This means that productions which
00927      * should have fired, dont.  However, if we comment this out for the
00928      * NO_TOP_LEVEL_REFS fix we don't seem to get this problem.  There might be
00929      * an underlying pathology here, but so far I don't know what it is.
00930      * This suspicion is heightened by the fact that even when this fix
00931      * is made, wmes are deallocated in a different place (e.g. at the end of
00932      * the input cycle) than using a normal build.
00933      *
00934      * an interesting aside seems to be that we don't need to do buffered
00935      * wme and own changes here regardless of whether or not L1R is used
00936      * so long as we test to make sure we're in the INPUT_PHASE.  I will 
00937      * look into this more later.
00938      */
00939 #ifndef NO_TOP_LEVEL_REFS
00940     do_buffered_wm_and_ownership_changes();
00941 #endif
00942 
00943 /* REW: begin 28.07.96 */
00944 #ifndef NO_TIMING_STUFF
00945     if (current_agent(current_phase) == INPUT_PHASE) {
00946 
00947 #ifndef KERNEL_TIME_ONLY
00948         stop_timer(&current_agent(start_phase_tv),
00949                    &current_agent(decision_cycle_phase_timers[current_agent(current_phase)]));
00950 #endif
00951         stop_timer(&current_agent(start_kernel_tv), &current_agent(total_kernel_time));
00952         start_timer(&current_agent(start_kernel_tv));
00953     }
00954 #endif
00955 /* REW: end 28.07.96 */
00956 /* #endif */
00957 
00958     *new_wme = (psoar_wme) w;
00959     return w->timetag;
00960 
00961 }
00962 
00963 /*
00964  *----------------------------------------------------------------------
00965  *
00966  * soar_cRemoveWmeUsingTimetag
00967  *
00968  *     Remove a working memory element, given its timetag
00969  *
00970  *     Note: this function essentially searches the entire working memory
00971  *     contents to find the given wme.  It is much more efficient to use
00972  *     the ancestor function, although it offers less encapsulation.
00973  *
00974  *     (calls the common RemoveWme ancestor: 
00975  *         soar_cRemoveWme)
00976  *
00977  *----------------------------------------------------------------------
00978  */
00979 int soar_cRemoveWmeUsingTimetag(int num)
00980 {
00981 
00982     wme *w;
00983 
00984     for (w = current_agent(all_wmes_in_rete); w != NIL; w = w->rete_next)
00985         if (w->timetag == (unsigned long) num)
00986             break;
00987 
00988     if (!w)
00989         return -1;
00990 
00991     if (!soar_cRemoveWme(w))
00992         return 0;
00993 
00994     return -2;                  /* Unspecified Failure */
00995 }
00996 
00997 /*
00998  *----------------------------------------------------------------------
00999  *
01000  * soar_cRemoveWme
01001  *
01002  *     Remove a working memory element, given a pointer to it.
01003  *
01004  *     (this function is the common ancestor of
01005  *      all other RemoveWme functions)
01006  *
01007  *----------------------------------------------------------------------
01008  */
01009 int soar_cRemoveWme(psoar_wme the_wme)
01010 {
01011 
01012     wme *w, *w2;
01013     Symbol *id;
01014     slot *s;
01015 
01016     w = (wme *) the_wme;
01017 
01018     id = w->id;
01019 
01020     /* --- remove w from whatever list of wmes it's on --- */
01021     for (w2 = id->id.input_wmes; w2 != NIL; w2 = w2->next)
01022         if (w == w2)
01023             break;
01024 
01025     if (w2)
01026         remove_from_dll(id->id.input_wmes, w, next, prev);
01027 
01028     for (w2 = id->id.impasse_wmes; w2 != NIL; w2 = w2->next)
01029         if (w == w2)
01030             break;
01031 
01032     if (w2)
01033         remove_from_dll(id->id.impasse_wmes, w, next, prev);
01034 
01035     for (s = id->id.slots; s != NIL; s = s->next) {
01036 
01037         for (w2 = s->wmes; w2 != NIL; w2 = w2->next)
01038             if (w == w2)
01039                 break;
01040 
01041         if (w2)
01042             remove_from_dll(s->wmes, w, next, prev);
01043 
01044         for (w2 = s->acceptable_preference_wmes; w2 != NIL; w2 = w2->next)
01045             if (w == w2)
01046                 break;
01047 
01048         if (w2)
01049             remove_from_dll(s->acceptable_preference_wmes, w, next, prev);
01050     }
01051 
01052 #ifdef USE_CAPTURE_REPLAY
01053 
01054     /* KJC 11/99 begin: */
01055     /* if input capturing is enabled, save any input changes to capture file */
01056     if (current_agent(capture_fileID) && (current_agent(current_phase) == INPUT_PHASE)) {
01057         soarapi_wme sapi_wme;
01058 
01059         sapi_wme.id = NULL;
01060         sapi_wme.attr = NULL;
01061         sapi_wme.value = NULL;
01062         sapi_wme.timetag = w->timetag;
01063 
01064         capture_input_wme(REMOVE_WME, &sapi_wme, NULL);
01065     }
01066     /* KJC 11/99 end */
01067 #endif                          /* USE_CAPTURE_REPLAY */
01068 
01069     /* REW: begin 09.15.96 */
01070 #ifndef SOAR_8_ONLY
01071     if (current_agent(operand2_mode)) {
01072 #endif
01073         if (w->gds) {
01074             if (w->gds->goal != NIL) {
01075 
01076                 gds_invalid_so_remove_goal(w);
01077 
01078                 /* NOTE: the call to remove_wme_from_wm will take care of checking if
01079                    GDS should be removed */
01080             }
01081         }
01082 #ifndef SOAR_8_ONLY
01083     }
01084 #endif
01085 
01086     /* REW: end   09.15.96 */
01087 
01088     /* --- now remove w from working memory --- */
01089     remove_wme_from_wm(w);
01090 
01091     /* REW: begin 28.07.96 */
01092     /* See AddWme for description of what's going on here */
01093 
01094     if (current_agent(current_phase) != INPUT_PHASE) {
01095 #ifndef NO_TIMING_STUFF
01096         start_timer(&current_agent(start_kernel_tv));
01097 #ifndef KERNEL_TIME_ONLY
01098         start_timer(&current_agent(start_phase_tv));
01099 #endif
01100 #endif
01101 
01102         /* do_buffered_wm_and_ownership_changes(); */
01103 
01104 #ifndef NO_TIMING_STUFF
01105 #ifndef KERNEL_TIME_ONLY
01106         stop_timer(&current_agent(start_phase_tv),
01107                    &current_agent(decision_cycle_phase_timers[current_agent(current_phase)]));
01108 #endif
01109         stop_timer(&current_agent(start_kernel_tv), &current_agent(total_kernel_time));
01110         start_timer(&current_agent(start_kernel_tv));
01111 #endif
01112     }
01113     /* note: 
01114      *  See note at the NO_TOP_LEVEL_REFS flag in soar_cAddWme
01115      */
01116 #ifndef NO_TOP_LEVEL_REFS
01117     do_buffered_wm_and_ownership_changes();
01118 #endif
01119 
01120     return 0;
01121 }
01122 
01123 /*
01124  *----------------------------------------------------------------------
01125  *
01126  * soar_cExciseAllProductions
01127  *
01128  *     Remove all productions from the agents memory and 
01129  *     ReInitialize the agent
01130  *
01131  *----------------------------------------------------------------------
01132  */
01133 void soar_cExciseAllProductions(void)
01134 {
01135 
01136     soar_cExciseAllProductionsOfType(DEFAULT_PRODUCTION_TYPE);
01137     soar_cExciseAllProductionsOfType(CHUNK_PRODUCTION_TYPE);
01138     soar_cExciseAllProductionsOfType(JUSTIFICATION_PRODUCTION_TYPE);
01139     soar_cExciseAllProductionsOfType(USER_PRODUCTION_TYPE);
01140     soar_cReInitSoar();
01141 }
01142 
01143 /*
01144  *----------------------------------------------------------------------
01145  *
01146  * soar_cExciseAllTaskProductions
01147  *
01148  *     Remove all but the default productions from the agents memory
01149  *     and ReInitialize the agent
01150  *
01151  *---------------------------------------------------------------------- 
01152  */
01153 
01154 void soar_cExciseAllTaskProductions(void)
01155 {
01156     soar_cExciseAllProductionsOfType(CHUNK_PRODUCTION_TYPE);
01157     soar_cExciseAllProductionsOfType(JUSTIFICATION_PRODUCTION_TYPE);
01158     soar_cExciseAllProductionsOfType(USER_PRODUCTION_TYPE);
01159     soar_cReInitSoar();
01160 }
01161 
01162 /*
01163  *----------------------------------------------------------------------
01164  *
01165  * soar_cExciseAllProductionsOfType
01166  *
01167  *     Remove all productions of a specific type from the agents
01168  *     memory
01169  *
01170  *---------------------------------------------------------------------- */
01171 
01172 void soar_cExciseAllProductionsOfType(byte type)
01173 {
01174     while (current_agent(all_productions_of_type)[type])
01175         excise_production(current_agent(all_productions_of_type)[type],
01176                           (bool) (TRUE && current_agent(sysparams)[TRACE_LOADING_SYSPARAM]));
01177 }
01178 
01179 /*
01180  *----------------------------------------------------------------------
01181  *
01182  * soar_cExciseProductionByName
01183  *
01184  *     Remove the production with the specified name
01185  *
01186  *----------------------------------------------------------------------
01187  */
01188 int soar_cExciseProductionByName(const char *name)
01189 {
01190     production *p;
01191 
01192     p = name_to_production(name);
01193     if (p) {
01194         excise_production(p, (bool) (TRUE && current_agent(sysparams)[TRACE_LOADING_SYSPARAM]));
01195         return 0;
01196     }
01197 
01198     return -1;                  /* production not found */
01199 }
01200 
01201 /* *************************************************************************
01202  * *************************************************************************
01203  *   
01204  * SECTION 3:    ACCESSING, MODIFYING & WATCHING THE AGENT'S STATE
01205  *
01206  *
01207  * *************************************************************************
01208  * *************************************************************************
01209  */
01210 
01211 #ifndef NO_TIMING_STUFF
01212 /*
01213  *----------------------------------------------------------------------
01214  *
01215  * soar_cDetermineTimerResolution
01216  *
01217  *   check the resolution of the system timers.     
01218  *
01219  *----------------------------------------------------------------------
01220  */
01221 double soar_cDetermineTimerResolution(double *min, double *max)
01222 {
01223 
01224     double delta, max_delta, min_delta, min_nz_delta;
01225     float q;
01226     int i, j, top;
01227 #ifdef PII_TIMERS
01228     unsigned long long int start, end, total;
01229 #else
01230     struct timeval start, end, total;
01231 #endif
01232 
01233     top = ONE_MILLION;
01234     min_delta = ONE_MILLION;
01235     min_nz_delta = ONE_MILLION;
01236     max_delta = -1;
01237     reset_timer(&total);
01238 
01239     for (i = 0; i < ONE_MILLION; i = (i + 1) * 2) {
01240         reset_timer(&end);
01241         start_timer(&start);
01242         for (j = 0; j < i * top; j++) {
01243             q = (float) (j * i);
01244         }
01245         stop_timer(&start, &end);
01246         stop_timer(&start, &total);
01247         delta = timer_value(&end);
01248 
01249         if (delta < min_delta)
01250             min_delta = delta;
01251         if (delta && delta < min_nz_delta)
01252             min_nz_delta = delta;
01253         if (delta > max_delta)
01254             max_delta = delta;
01255 
01256         /* when we have gone through this loop for 2 seconds, stop */
01257         if (timer_value(&total) >= 2) {
01258             break;
01259         }
01260 
01261     }
01262 
01263     if (min_nz_delta == ONE_MILLION)
01264         min_nz_delta = -1;
01265     if (min_delta == ONE_MILLION)
01266         min_delta = -1;
01267 
01268     if (min != NULL)
01269         *min = min_delta;
01270     if (max != NULL)
01271         *max = max_delta;
01272     return min_nz_delta;
01273 
01274 }
01275 #endif
01276 
01277 #ifdef DC_HISTOGRAM
01278 /*
01279  *----------------------------------------------------------------------
01280  *
01281  * soar_cInitializeDCHistogram
01282  *
01283  *     
01284  *
01285  *----------------------------------------------------------------------
01286  */
01287 void soar_cInitializeDCHistogram(int nDC, int freq)
01288 {
01289     int i;
01290 
01291     current_agent(dc_histogram_freq) = freq;
01292 
01293     if (nDC < current_agent(dc_histogram_sz)) {
01294         current_agent(dc_histogram_sz) = nDC;
01295     } else {
01296         free(current_agent(dc_histogram_tv));
01297         current_agent(dc_histogram_sz) = nDC;
01298         current_agent(dc_histogram_tv) = (struct timeval *) malloc(nDC * sizeof(struct timeval));
01299     }
01300 
01301     for (i = 0; i < nDC; i++) {
01302         reset_timer(&current_agent(dc_histogram_tv)[i]);
01303     }
01304 }
01305 #endif
01306 
01307 #ifdef KT_HISTOGRAM
01308 /*
01309  *----------------------------------------------------------------------
01310  *
01311  * soar_cInitializeKTHistogram
01312  *
01313  *     
01314  *
01315  *----------------------------------------------------------------------
01316  */
01317 void soar_cInitializeKTHistogram(int size)
01318 {
01319     int i;
01320 
01321     if (size < current_agent(kt_histogram_sz)) {
01322         current_agent(kt_histogram_sz) = size;
01323     } else {
01324         free(current_agent(kt_histogram_tv));
01325         current_agent(kt_histogram_sz) = size;
01326         current_agent(kt_histogram_tv) = (struct timeval *) malloc(size * sizeof(struct timeval));
01327     }
01328 
01329     for (i = 0; i < size; i++) {
01330         reset_timer(&current_agent(kt_histogram_tv)[i]);
01331     }
01332 }
01333 #endif
01334 
01335 /*
01336  *----------------------------------------------------------------------
01337  *
01338  * soar_cSetChunkNameLong
01339  *
01340  *     set long or short chunk names according to the specified
01341  *     parameter ( TRUE or FALSE respectively )
01342  *
01343  *----------------------------------------------------------------------
01344  */
01345 void soar_cSetChunkNameLong(bool truly)
01346 {
01347 
01348     set_sysparam(USE_LONG_CHUNK_NAMES, truly);
01349 
01350 }
01351 
01352 /*
01353  *----------------------------------------------------------------------
01354  *
01355  * soar_cSetChunkNameCount
01356  *
01357  *     set the chunk count.
01358  *       this must be greater than zero, less than max chunks and
01359  *       greater than the current chunk count.
01360  *
01361  *----------------------------------------------------------------------
01362  */
01363 int soar_cSetChunkNameCount(long count)
01364 {
01365 
01366     if (count < 0)
01367         return -1;
01368 
01369     if (count >= current_agent(sysparams)[MAX_CHUNKS_SYSPARAM])
01370         return -2;
01371 
01372     if ((unsigned long) count < current_agent(chunk_count))
01373         return -3;
01374 
01375     current_agent(chunk_count) = count;
01376     return 0;
01377 }
01378 
01379 /*
01380  *----------------------------------------------------------------------
01381  *
01382  * soar_cSetChunkNamePrefix
01383  *
01384  *     set long or short chunk names according to the specified
01385  *     parameter ( TRUE or FALSE respectively )
01386  *
01387  *----------------------------------------------------------------------
01388  */
01389 int soar_cSetChunkNamePrefix(const char *prefix)
01390 {
01391 
01392     if (strchr(prefix, '*')) {
01393         return -1;
01394     }
01395     strncpy(current_agent(chunk_name_prefix), prefix, kChunkNamePrefixMaxLength);
01396     current_agent(chunk_name_prefix)[kChunkNamePrefixMaxLength - 1] = 0;
01397     return 0;
01398 
01399 }
01400 
01401 /*
01402  *----------------------------------------------------------------------
01403  *
01404  * soar_cSetLearning
01405  *
01406  *       Adjust the learning settings
01407  *
01408  *----------------------------------------------------------------------
01409  */
01410 void soar_cSetLearning(enum soar_apiLearningSetting setting)
01411 {
01412 
01413     switch (setting) {
01414 
01415     case ON:
01416         set_sysparam(LEARNING_ON_SYSPARAM, TRUE);
01417         set_sysparam(LEARNING_ONLY_SYSPARAM, FALSE);
01418         set_sysparam(LEARNING_EXCEPT_SYSPARAM, FALSE);
01419         break;
01420     case OFF:
01421         set_sysparam(LEARNING_ON_SYSPARAM, FALSE);
01422         set_sysparam(LEARNING_ONLY_SYSPARAM, FALSE);
01423         set_sysparam(LEARNING_EXCEPT_SYSPARAM, FALSE);
01424         break;
01425     case ONLY:
01426         set_sysparam(LEARNING_ON_SYSPARAM, TRUE);
01427         set_sysparam(LEARNING_ONLY_SYSPARAM, TRUE);
01428         set_sysparam(LEARNING_EXCEPT_SYSPARAM, FALSE);
01429         break;
01430     case EXCEPT:
01431         set_sysparam(LEARNING_ON_SYSPARAM, TRUE);
01432         set_sysparam(LEARNING_ONLY_SYSPARAM, FALSE);
01433         set_sysparam(LEARNING_EXCEPT_SYSPARAM, TRUE);
01434         break;
01435     case ALL_LEVELS:
01436         set_sysparam(LEARNING_ALL_GOALS_SYSPARAM, TRUE);
01437         break;
01438     case BOTTOM_UP:
01439         set_sysparam(LEARNING_ALL_GOALS_SYSPARAM, FALSE);
01440         break;
01441 
01442     }
01443 
01444 }
01445 
01446 /*
01447  *----------------------------------------------------------------------
01448  *
01449  * soar_cSetOperand2
01450  *
01451  *----------------------------------------------------------------------
01452  */
01453 int soar_cSetOperand2(bool turnOn)
01454 {
01455     int i;
01456 
01457     /* --- check for empty system --- */
01458     if (current_agent(all_wmes_in_rete)) {
01459         return -1;
01460     }
01461     for (i = 0; i < NUM_PRODUCTION_TYPES; i++)
01462         if (current_agent(num_productions_of_type)[i]) {
01463             return -2;
01464         }
01465 
01466     current_agent(operand2_mode) = turnOn;
01467     soar_cReInitSoar();
01468 
01469     return 0;
01470 }
01471 
01472 /*
01473  *----------------------------------------------------------------------
01474  *
01475  * soar_cSetWaitSNC
01476  *
01477  *    if False, the agent generates State-No-Change impasses.
01478  *    otherwise, it just sits around waiting...
01479  *    
01480  *
01481  *----------------------------------------------------------------------
01482  */
01483 void soar_cSetWaitSNC(bool on)
01484 {
01485 
01486     current_agent(waitsnc) = on;
01487 }
01488 
01489 /*
01490  *----------------------------------------------------------------------
01491  *
01492  * soar_cMultiAttributes
01493  *
01494  *    Set the matching priority of a particular attribute
01495  *    
01496  *
01497  *----------------------------------------------------------------------
01498  */
01499 int soar_cMultiAttributes(const char *attribute, int value)
01500 {
01501     multi_attribute *m;
01502     Symbol *s;
01503 
01504     get_lexeme_from_string(attribute);
01505 
01506     if (current_agent(lexeme).type != SYM_CONSTANT_LEXEME) {
01507         return -1;
01508     }
01509     if (value < 1) {
01510         return -2;
01511     }
01512 
01513     m = current_agent(multi_attributes);
01514     s = make_sym_constant(attribute);
01515 
01516     while (m) {
01517         if (m->symbol == s) {
01518             m->value = value;
01519             symbol_remove_ref(s);
01520             return 0;
01521         }
01522         m = m->next;
01523     }
01524     /* sym wasn't in the table if we get here, so add it */
01525     m = (multi_attribute *) allocate_memory(sizeof(multi_attribute), MISCELLANEOUS_MEM_USAGE);
01526     m->value = value;
01527     m->symbol = s;
01528     m->next = current_agent(multi_attributes);
01529     current_agent(multi_attributes) = m;
01530 
01531     return 0;
01532 }
01533 
01534 /* 
01535  *----------------------------------------------------------------------
01536  *
01537  * soar_cAttributePreferencesMode
01538  *
01539  *           Determine how preferences for non-context slots should be 
01540  *           handled.  
01541  *----------------------------------------------------------------------
01542  */
01543 #ifndef SOAR_8_ONLY
01544 int soar_cAttributePreferencesMode(int mode)
01545 {
01546 
01547     if (current_agent(operand2_mode) && (mode != 2)) {
01548         /* we're in Soar8 mode, but tried setting mode != 2 */
01549 
01550         return -1;
01551     }
01552 
01553     if (mode >= 0 && mode <= 2) {
01554         current_agent(attribute_preferences_mode) = mode;
01555     } else {
01556         /*
01557          * Attribute Preferences Mode must be an integer 0, 1, or 2. 
01558          */
01559         return -2;
01560     }
01561 
01562     return 0;
01563 }
01564 
01565 #else
01566 
01567 int soar_cAttributePreferencesMode(int mode)
01568 {
01569 
01570     if (mode != 2) {
01571         /* we're in Soar8 mode, but tried setting mode != 2 */
01572 
01573         return -1;
01574     }
01575 
01576     return 0;
01577 }
01578 
01579 #endif                          /* SOAR_8_ONLY */
01580 
01581 /* *************************************************************************
01582  * *************************************************************************
01583  *   
01584  * SECTION 4:    CALLBACKS
01585  *
01586  *
01587  * *************************************************************************
01588  * *************************************************************************
01589  */
01590 
01591 /* ====================================================================
01592                   Adding New Input and Output Functions
01593 
01594    The system maintains a list of all the input functions to be called
01595    every input cycle, and another list of all the symbol-to-function
01596    mappings for output commands.  Add_input_function() and
01597    add_output_function() should be called at system startup time to 
01598    install each I/O function.
01599 ==================================================================== */
01600 
01601 /*
01602  *----------------------------------------------------------------------
01603  *
01604  * soar_cAddInputFunction
01605  *
01606  *     Installs a function which will provide input to the agent
01607  *
01608  *----------------------------------------------------------------------
01609  */
01610 void soar_cAddInputFunction(agent * a, soar_callback_fn f,
01611                             soar_callback_data cb_data, soar_callback_free_fn free_fn, const char *name)
01612 {
01613     soar_cAddCallback(a, INPUT_PHASE_CALLBACK, f, cb_data, free_fn, name);
01614 }
01615 
01616 /*
01617  *----------------------------------------------------------------------
01618  *
01619  * soar_cRemoveInputFunction
01620  *
01621  *     Remove a previously installed input function
01622  *
01623  *----------------------------------------------------------------------
01624  */
01625 void soar_cRemoveInputFunction(agent * a, const char *name)
01626 {
01627     soar_cRemoveCallback(a, INPUT_PHASE_CALLBACK, name);
01628 }
01629 
01630 /*
01631  *----------------------------------------------------------------------
01632  *
01633  * soar_cAddOutputFunction
01634  *
01635  *     Install a function to handle output from the agent
01636  *
01637  *----------------------------------------------------------------------
01638  */
01639 void soar_cAddOutputFunction(agent * a, soar_callback_fn f,
01640                              soar_callback_data cb_data, soar_callback_free_fn free_fn, const char *output_link_name)
01641 {
01642     if (soar_exists_callback_id(a, OUTPUT_PHASE_CALLBACK, output_link_name)
01643         != NULL) {
01644         print("Error: tried to add_output_function with duplicate name %s\n", output_link_name);
01645         control_c_handler(0);
01646     } else {
01647         soar_cAddCallback(a, OUTPUT_PHASE_CALLBACK, f, cb_data, free_fn, output_link_name);
01648     }
01649 }
01650 
01651 /*
01652  *----------------------------------------------------------------------
01653  *
01654  * soar_cRemoveOutputFunction
01655  *
01656  *     Remove a previously installed output function
01657  *
01658  *----------------------------------------------------------------------
01659  */
01660 void soar_cRemoveOutputFunction(agent * a, const char *name)
01661 {
01662     soar_callback *cb;
01663     output_link *ol;
01664 
01665     /* Remove indexing structures ... */
01666 
01667     cb = soar_exists_callback_id(a, OUTPUT_PHASE_CALLBACK, name);
01668     if (!cb)
01669         return;
01670 
01671     for (ol = a->existing_output_links; ol != NIL; ol = ol->next) {
01672         if (ol->cb == cb) {
01673             /* Remove ol entry */
01674             ol->link_wme->output_link = NULL;
01675             wme_remove_ref(ol->link_wme);
01676             remove_from_dll(a->existing_output_links, ol, next, prev);
01677             free_with_pool(&(a->output_link_pool), ol);
01678             break;
01679         }
01680     }
01681 
01682     soar_cRemoveCallback(a, OUTPUT_PHASE_CALLBACK, name);
01683 }
01684 
01685 /*
01686  *----------------------------------------------------------------------
01687  *
01688  * soar_cPushCallback
01689  *
01690  *
01691  *----------------------------------------------------------------------
01692  */
01693 void soar_cPushCallback(soar_callback_agent the_agent,
01694                         SOAR_CALLBACK_TYPE callback_type,
01695                         soar_callback_fn fn, soar_callback_data data, soar_callback_free_fn free_fn)
01696 {
01697     soar_callback *cb;
01698 
01699     cb = (soar_callback *) malloc(sizeof(soar_callback));
01700     cb->function = fn;
01701     cb->data = data;
01702     cb->free_function = free_fn;
01703     cb->id = NULL;
01704 
01705 /*
01706   printf( "Pushing callback function %p onto callback slot %d\n", 
01707         fn, callback_type );
01708   fflush( stdout );
01709 */
01710 
01711     push(cb, ((agent *) the_agent)->soar_callbacks[callback_type]);
01712 }
01713 
01714 /*
01715  *----------------------------------------------------------------------
01716  *
01717  * soar_cAddCallback
01718  *
01719  *
01720  *----------------------------------------------------------------------
01721  */
01722 void soar_cAddCallback(soar_callback_agent the_agent,
01723                        SOAR_CALLBACK_TYPE callback_type,
01724                        soar_callback_fn fn, soar_callback_data data, soar_callback_free_fn free_fn, soar_callback_id id)
01725 {
01726     soar_callback *cb;
01727 
01728     cb = (soar_callback *) malloc(sizeof(soar_callback));
01729     cb->function = fn;
01730     cb->data = data;
01731     cb->free_function = free_fn;
01732     cb->id = savestring((char *) id);
01733 
01734     push(cb, ((agent *) the_agent)->soar_callbacks[callback_type]);
01735 }
01736 
01737 /*
01738  *----------------------------------------------------------------------
01739  *
01740  * soar_cPopCallback
01741  *
01742  *
01743  *----------------------------------------------------------------------
01744  */
01745 void soar_cPopCallback(soar_callback_agent the_agent, SOAR_CALLBACK_TYPE callback_type)
01746 {
01747     list *head;
01748     soar_callback *cb;
01749 
01750     head = ((agent *) the_agent)->soar_callbacks[callback_type];
01751 
01752     if (head == NULL) {
01753         print_string("Attempt to remove non-existant callback.\n");
01754         return;
01755     }
01756 
01757     if ((callback_type == PRINT_CALLBACK)
01758         && (head->rest == NULL)) {
01759         print_string("Attempt to remove last print callback. Ignored.\n");
01760         return;
01761     }
01762 
01763     cb = (soar_callback *) head->first;
01764 
01765     ((agent *) the_agent)->soar_callbacks[callback_type] = head->rest;
01766     soar_destroy_callback(cb);
01767     free_cons(head);
01768 }
01769 
01770 /*
01771  *----------------------------------------------------------------------
01772  *
01773  * soar_cRemoveCallback
01774  *
01775  *
01776  *----------------------------------------------------------------------
01777  */
01778 void soar_cRemoveCallback(soar_callback_agent the_agent, SOAR_CALLBACK_TYPE callback_type, soar_callback_id id)
01779 {
01780     cons *c;
01781     cons *prev_c = NULL;        /* Initialized to placate gcc -Wall */
01782     list *head;
01783 
01784     head = ((agent *) the_agent)->soar_callbacks[callback_type];
01785 
01786         /* This is a non-standard for loop.
01787            Because we have to juggle the elements of this list around as we are
01788            deleting them, it is difficult to ensure that we can use a single
01789            incrementer, like c = c->rest.  The primary problem is that, if we
01790            delete the last item in the list, then the incrementer will fail
01791            (since c will be NULL).  Because of this, we manually increment the list
01792            inside the loop based on what the circumstances are.  Thus, the statements
01793            which change the value of c are the incrementers.
01794         */
01795 
01796     for (c = head; c != NULL; /*c = c->rest*/) {
01797         soar_callback *cb;
01798 
01799         cb = (soar_callback *) c->first;
01800 
01801         if (!strcmp(cb->id, id)) {
01802             if (c != head) {
01803                 prev_c->rest = c->rest;
01804                 soar_destroy_callback(cb);
01805                 free_cons(c);
01806                                 c = prev_c->rest;
01807                 /*return;*/
01808             } else {
01809                 ((agent *) the_agent)->soar_callbacks[callback_type]
01810                     = head->rest;
01811                 soar_destroy_callback(cb);
01812                 free_cons(c);
01813                                 head = ((agent *) the_agent)->soar_callbacks[callback_type]; 
01814                                 c = head;
01815                                 prev_c = NULL;
01816                 /*return;*/
01817             }
01818 
01819         }
01820                 else {
01821                         prev_c = c;
01822                         c = c->rest;
01823 
01824                 }
01825 
01826         /*prev_c = c;*/
01827     }
01828 }
01829 
01830 /*
01831  *----------------------------------------------------------------------
01832  *
01833  * soar_cAddGlobalCallback
01834  *
01835  *
01836  *----------------------------------------------------------------------
01837  */
01838 void soar_cAddGlobalCallback(SOAR_GLOBAL_CALLBACK_TYPE callback_type,
01839                              soar_callback_fn fn,
01840                              soar_callback_data data, soar_callback_free_fn free_fn, soar_callback_id id)
01841 {
01842     soar_callback *cb;
01843 
01844     cb = (soar_callback *) malloc(sizeof(soar_callback));
01845     cb->function = fn;
01846     cb->data = data;
01847     cb->free_function = free_fn;
01848     cb->id = savestring((char *) id);
01849 
01850     /* We can't use the push macro because it allocates memory
01851      *  from an agent's memory pool.
01852      */
01853     {
01854         cons *push_cons_xy298;
01855         push_cons_xy298 = (cons *) malloc(sizeof(cons));
01856         push_cons_xy298->first = (cb);
01857         push_cons_xy298->rest = (soar_global_callbacks[callback_type]);
01858         soar_global_callbacks[callback_type] = push_cons_xy298;
01859     }
01860 
01861 }
01862 
01863 /*
01864  *----------------------------------------------------------------------
01865  *
01866  * soar_cRemoveGlobalCallback
01867  *
01868  *
01869  *----------------------------------------------------------------------
01870  */
01871 void soar_cRemoveGlobalCallback(SOAR_GLOBAL_CALLBACK_TYPE callback_type, soar_callback_id id)
01872 {
01873     list *head;
01874     cons *c;
01875     cons *prev_c = NULL;        /* Initialized to placate gcc -Wall */
01876     soar_callback *cb;
01877 
01878     head = soar_global_callbacks[callback_type];
01879 
01880     for (c = head; c != NIL; c = c->rest) {
01881 
01882         cb = (soar_callback *) c->first;
01883 
01884         if (!strcmp(cb->id, id)) {
01885             if (c != head) {
01886                 prev_c->rest = c->rest;
01887                 soar_destroy_callback(cb);
01888                 free_cons(c);
01889                 return;
01890             } else {
01891                 soar_global_callbacks[callback_type] = head->rest;
01892                 soar_destroy_callback(cb);
01893                 free_cons(c);
01894                 return;
01895             }
01896         }
01897         prev_c = c;
01898     }
01899 }
01900 
01901 void soar_cListAllCallbacks(soar_callback_agent the_agent, bool monitorable_only)
01902 {
01903     int limit;
01904     SOAR_CALLBACK_TYPE ct;
01905 
01906     if (monitorable_only) {
01907         limit = NUMBER_OF_MONITORABLE_CALLBACKS;
01908     } else {
01909         limit = NUMBER_OF_CALLBACKS;
01910     }
01911 
01912     for (ct = 1; ct < limit; ct++) {
01913         print("%s: ", soar_callback_enum_to_name(ct, FALSE));
01914         soar_cListAllCallbacksForEvent(the_agent, ct);
01915         print("\n");
01916     }
01917 }
01918 
01919 void soar_cListAllCallbacksForEvent(soar_callback_agent the_agent, SOAR_CALLBACK_TYPE ct)
01920 {
01921     cons *c;
01922 
01923     for (c = ((agent *) the_agent)->soar_callbacks[ct]; c != NIL; c = c->rest) {
01924         soar_callback *cb;
01925 
01926         cb = (soar_callback *) c->first;
01927 
01928         print("%s ", cb->id);
01929     }
01930 }
01931 
01932 void soar_cRemoveAllMonitorableCallbacks(soar_callback_agent the_agent)
01933 {
01934     SOAR_CALLBACK_TYPE ct;
01935 
01936     for (ct = 1; ct < NUMBER_OF_MONITORABLE_CALLBACKS; ct++) {
01937         soar_cRemoveAllCallbacksForEvent(the_agent, ct);
01938     }
01939 }
01940 
01941 void soar_cRemoveAllCallbacksForEvent(soar_callback_agent the_agent, SOAR_CALLBACK_TYPE ct)
01942 {
01943     cons *c;
01944     list *next;
01945 
01946     next = ((agent *) the_agent)->soar_callbacks[ct];
01947 
01948     for (c = next; c != NIL; c = next) {
01949         soar_callback *cb;
01950 
01951         cb = (soar_callback *) c->first;
01952 
01953         next = next->rest;
01954         soar_destroy_callback(cb);
01955         free_cons(c);
01956     }
01957 
01958     ((agent *) the_agent)->soar_callbacks[ct] = NIL;
01959 }
01960 
01961 void soar_cTestAllMonitorableCallbacks(soar_callback_agent the_agent)
01962 {
01963     SOAR_CALLBACK_TYPE i;
01964     static char *test_callback_name = "test";
01965 
01966     for (i = 1; i < NUMBER_OF_MONITORABLE_CALLBACKS; i++) {
01967         soar_cAddCallback(the_agent, i,
01968                           (soar_callback_fn) soar_cTestCallback,
01969                           soar_callback_enum_to_name(i, TRUE), NULL, test_callback_name);
01970     }
01971 }
01972 
01973 SOAR_CALLBACK_TYPE soar_cCallbackNameToEnum(const char *name, bool monitorable_only)
01974 {
01975     int limit;
01976     SOAR_CALLBACK_TYPE i;
01977 
01978     if (monitorable_only) {
01979         limit = NUMBER_OF_MONITORABLE_CALLBACKS;
01980     } else {
01981         limit = NUMBER_OF_CALLBACKS;
01982     }
01983 
01984     for (i = 1; i < limit; i++) {
01985         if (!strcmp(name, soar_callback_names[i])) {
01986             return i;
01987         }
01988     }
01989 
01990     return NO_CALLBACK;
01991 }
01992 
01993 /* *************************************************************************
01994  * *************************************************************************
01995  *   
01996  * SECTION 5:    ETC
01997  *
01998  *
01999  *               - Wme Accessors
02000  *               - AddWme Wrappers
02001  *               - Multi Agent Controls
02002  *
02003  * *************************************************************************
02004  * *************************************************************************
02005  */
02006 
02007 /*
02008  * string must be freed using free()
02009  * I am refraining from using Soar's internal memory because strings,
02010  * like all other memory pools are allocated on a per-agent basis.
02011  * This means that the user would have to ensure that the same agent
02012  * was selected when one of the wme accessor functions was called 
02013  * as was selected when the returned string was freed.  Otherwise,
02014  * untold things could happen.  Thus here, I opt for the potentially
02015  * slower, but safer, accessor function.
02016  */
02017 char *soar_cGetWmeId(psoar_wme w, char *buff, size_t buff_size)
02018 {
02019     char *temp;
02020     char *ret;
02021 
02022     temp = symbol_to_string(((wme *) w)->id, TRUE, buff, buff_size);
02023     if (buff)
02024         return buff;
02025 
02026     ret = (char *) malloc((strlen(temp) + 1) * sizeof(char));
02027     strcpy(ret, temp);          /* this is relatively safe since the memory is allocated on the previous line */
02028 
02029     return ret;
02030 }
02031 
02032 char *soar_cGetWmeAttr(psoar_wme w, char *buff, size_t buff_size)
02033 {
02034     char *temp;
02035     char *ret;
02036 
02037     temp = symbol_to_string(((wme *) w)->attr, TRUE, buff, buff_size);
02038     if (buff)
02039         return buff;
02040 
02041     ret = (char *) malloc((strlen(temp) + 1) * sizeof(char));
02042     strcpy(ret, temp);          /* this is relatively safe since the memory is allocated on the previous line */
02043 
02044     return ret;
02045 
02046 }
02047 
02048 char *soar_cGetWmeValue(psoar_wme w, char *buff, size_t buff_size)
02049 {
02050     char *temp;
02051     char *ret;
02052 
02053     temp = symbol_to_string(((wme *) w)->value, TRUE, buff, buff_size);
02054     if (buff)
02055         return buff;
02056 
02057     ret = (char *) malloc((strlen(temp) + 1) * sizeof(char));
02058     strcpy(ret, temp);          /* this is relatively safe since the memory is allocated on the previous line */
02059 
02060     return ret;
02061 
02062 }
02063 
02064 unsigned long soar_cGetWmeTimetag(psoar_wme w)
02065 {
02066     return ((wme *) w)->timetag;
02067 }
02068 
02069 #define SOAR_CADDINTWME_TEMP_SIZE 128
02070 unsigned long soar_cAddIntWme(char *szId, char *szAttr, int value, bool acceptable, psoar_wme * w)
02071 {
02072     char temp[SOAR_CADDINTWME_TEMP_SIZE];
02073 
02074     snprintf(temp, SOAR_CADDINTWME_TEMP_SIZE, "%d", value);
02075     temp[SOAR_CADDINTWME_TEMP_SIZE - 1] = 0;    /* snprintf doesn't set last char to null if output is truncated */
02076 
02077     return soar_cAddWme(szId, szAttr, temp, acceptable, w);
02078 }
02079 
02080 #define SOAR_CADDFLOATWME_TEMP_SIZE 128
02081 unsigned long soar_cAddFloatWme(char *szId, char *szAttr, float value, bool acceptable, psoar_wme * w)
02082 {
02083     char temp[SOAR_CADDFLOATWME_TEMP_SIZE];
02084 
02085     snprintf(temp, SOAR_CADDFLOATWME_TEMP_SIZE, "%f", value);
02086     temp[SOAR_CADDFLOATWME_TEMP_SIZE - 1] = 0;  /* snprintf doesn't set last char to null if output is truncated */
02087 
02088     return soar_cAddWme(szId, szAttr, temp, acceptable, w);
02089 }
02090 
02091 void soar_cInitAgentIterator(soar_apiAgentIterator * ai)
02092 {
02093     cons *c;
02094 
02095     ai->_begin = NIL;
02096 
02097     for (c = all_soar_agents; c != NIL; c = c->rest) {
02098         if (((agent *) c->first) == soar_agent) {
02099             ai->_begin = c;
02100             ai->_current = c;
02101             ai->more = (bool) ((agent_count > 0) ? TRUE : FALSE);
02102         }
02103     }
02104     if (ai->_begin == NIL) {
02105         print("ERROR!!!!!!!!!!");
02106     }
02107 
02108 }
02109 
02110 bool soar_cStepAgentIterator(soar_apiAgentIterator * ai)
02111 {
02112 
02113     ai->_current = ai->_current->rest;
02114     if (ai->_current == NIL) {
02115         ai->_current = all_soar_agents; /* cycle to beginning of list */
02116     }
02117     ai->more = TRUE;
02118 
02119     if (ai->_current == ai->_begin) {
02120         ai->more = FALSE;
02121     } else if (ai->_current->rest == NIL && all_soar_agents == ai->_current) {
02122         ai->more = FALSE;
02123     }
02124 
02125     soar_agent = ai->_current->first;
02126 
02127     return ai->more;
02128 }
02129 
02130 psoar_agent soar_cGetAgentByName(char *name)
02131 {
02132     cons *c;
02133 
02134     for (c = all_soar_agents; c != NIL; c = c->rest) {
02135         if (!strcmp(((agent *) c->first)->name, name)) {
02136             return (psoar_agent) c->first;
02137         }
02138     }
02139     return NIL;
02140 
02141 }
02142 
02143 int soar_cGetIdForAgentByName(char *name)
02144 {
02145     psoar_agent a;
02146 
02147     a = soar_cGetAgentByName(name);
02148     if (!a)
02149         return -1;
02150 
02151     return ((agent *) a)->id;
02152 
02153 }
02154 
02155 bool soar_cSetCurrentAgentByName(char *name)
02156 {
02157     psoar_agent a;
02158 
02159     a = soar_cGetAgentByName(name);
02160     if (!a)
02161         return FALSE;
02162 
02163     soar_agent = (agent *) a;
02164     return TRUE;
02165 }
02166 
02167 void soar_cSetCurrentAgent(psoar_agent a)
02168 {
02169 
02170     soar_agent = (agent *) a;
02171 }
02172 
02173 psoar_agent soar_cGetCurrentAgent()
02174 {
02175     return (psoar_agent) soar_agent;
02176 }
02177 
02178 /*
02179  * string must be freed using free()
02180  * I am refraining from using Soar's internal memory because strings,
02181  * like all other memory pools are allocated on a per-agent basis.
02182  * This means that the user would have to ensure that the same agent
02183  * was selected when  the accessor function was called 
02184  * as was selected when the returned string was freed.  Otherwise,
02185  * untold things could happen.  Thus here, I opt for the potentially
02186  * slower, but safer, accessor function.
02187  */
02188 
02189 char *soar_cGetAgentInputLinkId(psoar_agent a, char *buff, size_t buff_size)
02190 {
02191     char *temp;
02192     char *ret;
02193 
02194     if (((agent *) a)->io_header_input == NULL) {
02195         if (buff)
02196             *buff = '\0';
02197         return "";
02198     }
02199 
02200     temp = symbol_to_string(((agent *) a)->io_header_input, TRUE, buff, buff_size);
02201     if (buff)
02202         return buff;
02203 
02204     ret = (char *) malloc((strlen(temp) + 1) * sizeof(char));
02205     strcpy(ret, temp);          /* this is relatively safe since the memory is allocated on the previous line */
02206 
02207     return ret;
02208 }
02209 
02210 char *soar_cGetAgentOutputLinkId(psoar_agent a, char *buff, size_t buff_size)
02211 {
02212     char *temp;
02213     char *ret;
02214 
02215     if (((agent *) a)->io_header_output == NULL) {
02216         if (buff)
02217             *buff = '\0';
02218         return "";
02219     }
02220 
02221     temp = symbol_to_string(((agent *) a)->io_header_output, TRUE, buff, buff_size);
02222     if (buff)
02223         return buff;
02224 
02225     ret = (char *) malloc((strlen(temp) + 1) * sizeof(char));
02226     strcpy(ret, temp);          /* this is relatively safe since the memory is allocated on the previous line */
02227 
02228     return ret;
02229 }
02230 
02231 int soar_cGetAgentId(psoar_agent a)
02232 {
02233 
02234     if (a == NULL)
02235         return -1;
02236 
02237     return ((agent *) a)->id;
02238 }
02239 
02240 void soar_cTestCallback(soar_callback_agent the_agent, soar_callback_data data, soar_call_data call_data)
02241 {
02242     the_agent = the_agent;      /* stops compiler warning */
02243     call_data = call_data;      /* stops compiler warning */
02244 
02245     print("%s test callback executed.\n", (char *) data);
02246 }
02247 
02248 #define SOAR_CDEFAULTASKCALLBACK_TEMP_SIZE 50
02249 void soar_cDefaultAskCallback(soar_callback_agent the_agent, soar_callback_data data, soar_call_data call_data)
02250 {
02251 
02252     int num_candidates, chosen_num;
02253     preference *cand;
02254 
02255     the_agent = the_agent;      /* stops compiler warning */
02256     data = data;                /* stops compiler warning */
02257 
02258     *((soar_apiAskCallbackData *) call_data)->selection = NULL;
02259 
02260     num_candidates = 0;
02261     print("\nPlease choose one of the following:\n");
02262     for (cand = ((soar_apiAskCallbackData *) call_data)->candidates; cand != NIL; cand = cand->next_candidate) {
02263 
02264         num_candidates++;
02265         print("  %d:  ", num_candidates);
02266         print_object_trace(cand->value);
02267         print("\n");
02268     }
02269 
02270     /* AGR 615 begin */
02271     print("Or choose one of the following to change the user-select mode\n");
02272     print("to something else:  %d (first)", ++num_candidates);
02273     print(", %d (last)", ++num_candidates);
02274     print(", %d (random)\n", ++num_candidates);
02275     /* AGR 615 end */
02276     for (;;) {
02277         char ch;
02278 
02279         /*  char buf[256]; *//* kjh(CUSP-B10) */
02280         print("Enter selection (1-%d): ", num_candidates);
02281         chosen_num = -1;
02282         scanf(" %d", &chosen_num);
02283         do {
02284             ch = (char) getchar();
02285         } while ((ch != '\n') && (ch != EOF_AS_CHAR));
02286 
02287         if (ch == EOF_AS_CHAR)
02288             clearerr(stdin);    /* Soar-Bugs #103, TMH */
02289 
02290         /* kjh(CUSP-B10) BEGIN */
02291         /* Soar_Read(soar_agent, buf, 256);
02292            sscanf(buf,"%d",&chosen_num); */
02293         /* kjh(CUSP-B10) END */
02294 
02295         if ((chosen_num >= 1) && (chosen_num <= num_candidates))
02296             break;
02297         print("You must enter a number between 1 and %d\n", num_candidates);
02298     }
02299     if (current_agent(logging_to_file)) {
02300         char temp[SOAR_CDEFAULTASKCALLBACK_TEMP_SIZE];
02301         snprintf(temp, SOAR_CDEFAULTASKCALLBACK_TEMP_SIZE, "%d\n", chosen_num);
02302         temp[SOAR_CDEFAULTASKCALLBACK_TEMP_SIZE - 1] = 0;       /* snprintf doesn't set last char to null if output is truncated */
02303         print_string_to_log_file_only(temp);
02304     }
02305     /* AGR 615 begin */
02306     switch (num_candidates - chosen_num) {
02307 
02308     case 2:
02309         set_sysparam(USER_SELECT_MODE_SYSPARAM, USER_SELECT_FIRST);
02310         print("User-select mode changed to:  first\n");
02311         *((soar_apiAskCallbackData *) call_data)->selection = ((soar_apiAskCallbackData *) call_data)->candidates;
02312         break;
02313 
02314     case 1:
02315         set_sysparam(USER_SELECT_MODE_SYSPARAM, USER_SELECT_LAST);
02316         print("User-select mode changed to:  last\n");
02317         for (cand = ((soar_apiAskCallbackData *) call_data)->candidates;
02318              cand->next_candidate != NIL; cand = cand->next_candidate);
02319 
02320         *((soar_apiAskCallbackData *) call_data)->selection = cand;
02321         break;
02322 
02323     case 0:
02324         set_sysparam(USER_SELECT_MODE_SYSPARAM, USER_SELECT_RANDOM);
02325         print("User-select mode changed to:  random\n");
02326 
02327         chosen_num = sys_random() % (num_candidates - 3);
02328 
02329         cand = ((soar_apiAskCallbackData *) call_data)->candidates;
02330         while (chosen_num) {
02331             cand = cand->next_candidate;
02332             chosen_num--;
02333         }
02334         *((soar_apiAskCallbackData *) call_data)->selection = cand;
02335         break;
02336 
02337     default:
02338         cand = ((soar_apiAskCallbackData *) call_data)->candidates;
02339         while (chosen_num > 1) {
02340             cand = cand->next_candidate;
02341             chosen_num--;
02342         }
02343         *((soar_apiAskCallbackData *) call_data)->selection = cand;
02344     }
02345     /* AGR 615 end */
02346 
02347     return;
02348 }

Generated on Thu Dec 11 13:00:21 2003 for Soar Kernel by doxygen 1.3.5