/*
   script_library.c

   bf 11-28-96
*/

/// Includes
#include <string.h>
#include <exec/memory.h>
#include <rexx/rxslib.h>
#include <rexx/storage.h>
#include <proto/rexxsyslib.h>
#include <proto/exec.h>

#if defined (__GNUC__)
#include <stabs.h>
#endif

#include "script_library.h"
#include "variables.h"
///

/// Declarations
struct ScriptContext *AllocContext (void);
void FreeContext (struct ScriptContext *sc);

struct ExecBase *SysBase;
struct Library *ScriptBase;

#if defined (__GNUC__)
const BYTE LibName[] = "script.library";
const BYTE LibIdString[] = "$VER: script.library 0.4 (12-20-96)";
const UWORD LibVersion = 0;
const UWORD LibRevision = 4;
#endif

#if defined (__GNUC__)
#define LIBRT
#define REG(regname)
#define STRUCT_MYLIB struct Library
#elif defined (__SASC)
#define LIBRT __saveds __asm
#define REG(regname) register __ ## regname
#define ADDTABL_1(name,arg1);
#define ADDTABL_2(name,arg1,arg2);
#define ADDTABL_3(name,arg1,arg2,arg3);
#define ADDTABL_END();
#define STRUCT_MYLIB struct MyLibrary
#endif
///

/// Library (De)Initialization
int LIBRT
__UserLibInit (REG(a6) STRUCT_MYLIB *libbase)
{
  SysBase = *(struct ExecBase **)4;
  ScriptBase = (struct Library *) libbase;
  return 0; /* success */
}

void LIBRT
__UserLibCleanup (REG(a6) STRUCT_MYLIB *libbase)
{
}
///

ADDTABL_3(LIBScript_SetRexxVar,a0,a1,a2);

/// Script_SetRexxVar()
/*
   Script_SetRexxVar() is compatible with SetRexxVar():

   RESULTS
        error            0 for success, otherwise an error code.
                         (Other codes may exist, these are documented)
                         3 = Insufficient Storage
                         9 = String too long
                        10 = Invalid message

   NOTE
        The rm_avail field of a RexxMsg bust be zeroed or point to
        a ScriptContext structure allocated by Script_AllocContext().
*/
LONG LIBRT
LIBScript_SetRexxVar (REG(a0) struct RexxMsg *msg, REG(a1) char *name, REG(a2) char *value)
{
  struct ScriptContext *sc;
  LONG err;

  if (CheckRexxMsg (msg))
  {
    // Without this CheckRexxMsg() SetRexxVar() causes Enforcer Hits at this point!
    // This is weird since the docs say SetRexxVar() does a CheckRexxMsg() on msg.
    //
    if ((err = SetRexxVar ((struct Message *) msg, name, value, strlen (value))) != 10)
      return err;
  }
  if (sc = (struct ScriptContext *) msg -> rm_avail)
  {
    if (SetStringVariable (sc, name, value))
      return 0;
    return 3;
  }
  return 10;
}
///

ADDTABL_3(LIBScript_GetRexxVar,a0,a1,a2);

/// Script_GetRexxVar()
/*
   Script_GetRexxVar() is compatible with GetRexxVar():

   RESULTS
        error            0 for success, otherwise an error code.
                         (Other codes may exist, these are documented)
                         3 = Insufficient Storage
                         9 = String too long
                        10 = Invalid message
   NOTE
        The rm_avail field of a RexxMsg bust be zeroed or point to
        a ScriptContext structure allocated by Script_AllocContext().
*/
LONG LIBRT
LIBScript_GetRexxVar (REG(a0) struct RexxMsg *msg, REG(a1) char *name, REG(a2) char **value)
{
  struct ScriptContext *sc;
  LONG err;

  *value = NULL;

  if ((err = GetRexxVar ((struct Message *) msg, name, (UBYTE **) value)) != 10)
    return err;

  if (sc = (struct ScriptContext *) msg -> rm_avail)
  {
    *value = GetStringVariable (sc, name);
    return 0;
  }
  return 10;
}
///

ADDTABL_1(LIBScript_AllocContext,a0);

/// Script_AllocContext()
struct ScriptContext * LIBRT
LIBScript_AllocContext (void)
{
  return AllocContext ();
}

struct ScriptContext *
AllocContext (void)
{
  struct ScriptContext *sc = NULL;
  void *pool = NULL;

  if (!(pool = CreatePool (MEMF_PUBLIC, 1024, 1024)))
    return NULL;

  if (!(sc = AllocPooled (pool, sizeof (struct ScriptContext))))
  {
    DeletePool (pool);
    return NULL;
  }
  NewList ((struct List *) &sc -> sc_Vars);
  sc -> sc_MemPool = pool;
  return sc;
}
///

ADDTABL_1(LIBScript_FreeContext,a0);

/// Script_FreeContext()
void LIBRT
LIBScript_FreeContext (REG(a0) struct ScriptContext *sc)
{
  FreeContext (sc);
}

void
FreeContext (struct ScriptContext *sc)
{
  DeletePool (sc -> sc_MemPool);
}
///

ADDTABL_2(LIBScript_SetMsgContext,a0,a1);

/// Script_SetMsgContext()
/*
   It may appear silly to have an extra function just to make this assignment but
   rm_avail is not officially reserved to contain "struct ScriptContext *" and
   future versions of script.library may have to use a different method.
   Maybe "msg -> rm_Node.mn_Node.ln_Name" or "msg -> rm_ScriptContext" :)

   Please use Script_SetMsgContext() and don't access rm_avail directly!
*/
void LIBRT
LIBScript_SetMsgContext (REG(a0) struct RexxMsg *msg, REG(a1) struct ScriptContext *sc)
{
  msg -> rm_avail = (long) sc;
}
///

ADDTABL_1(LIBScript_GetMsgContext,a0);

/// Script_GetMsgContext()
struct ScriptContext * LIBRT
LIBScript_GetMsgContext (REG(a0) struct RexxMsg *msg)
{
  return (struct ScriptContext *) msg -> rm_avail;
}
///

ADDTABL_3(LIBScript_SetStringVar,a0,a1,a2);

/// Script_SetStringVar()
LONG LIBRT
LIBScript_SetStringVar (REG(a0) struct ScriptContext *sc, REG(a1) char *name, REG(a2) char *value)
{
  if (SetStringVariable (sc, name, value))
    return 0;
  return 3;
}
///

ADDTABL_3(LIBScript_GetStringVar,a0,a1,a2);

/// Script_GetStringVar()
LONG LIBRT
LIBScript_GetStringVar (REG(a0) struct ScriptContext *sc, REG(a1) char *name, REG(a2) char **value)
{
  *value = GetStringVariable (sc, name);
  return 0;
}
///

ADDTABL_END();
