diff --git a/library/amiga_rexxvars.c b/library/amiga_rexxvars.c index 2aa6bc3..fb37d66 100644 --- a/library/amiga_rexxvars.c +++ b/library/amiga_rexxvars.c @@ -1,5 +1,5 @@ /* - * $Id: amiga_rexxvars.c,v 1.12 2008-03-11 13:26:18 obarthel Exp $ + * $Id: amiga_rexxvars.c,v 1.13 2008-04-14 15:07:37 obarthel Exp $ * * :ts=4 * @@ -53,6 +53,10 @@ /****************************************************************************/ +struct Environment; + +/****************************************************************************/ + #define __NOLIBBASE__ #include @@ -124,7 +128,7 @@ static struct RexxSysIFace * IRexxSys; BOOL CheckRexxMsg(struct RexxMsg *message); LONG GetRexxVar(struct RexxMsg *message,STRPTR variable_name,STRPTR *buffer_pointer); -LONG SetRexxVar(struct RexxMsg *message,STRPTR variable_name,STRPTR value,ULONG length); +LONG SetRexxVar(struct RexxMsg *message,STRPTR variable_name,STRPTR value,LONG length); /****************************************************************************/ @@ -208,6 +212,10 @@ CheckRexxMsg(struct RexxMsg *message) /****************************************************************************/ +#if 1 + +/****************************************************************************/ + /* The following function works in about like the original, except that it's not reentrant, does not fill in a pointer to the variable itself and requires rexxsyslib.library V45. */ @@ -261,3 +269,437 @@ SetRexxVar(struct RexxMsg *message,STRPTR variable_name,STRPTR value,ULONG lengt return(result); } + +/****************************************************************************/ + +#else + +/****************************************************************************/ + +#if defined(__GNUC__) && !defined(__amigaos4__) + +/****************************************************************************/ + +/* A selection of lovingly hand-crafted 68k stub functions which call + into rexxsyslib.library LVOs which still used to be documented back + in 1987. */ + +/****************************************************************************/ + +#if defined(SMALL_DATA) +#define A4(x) "a4@(" #x ":W)" +#elif defined(SMALL_DATA32) +#define A4(x) "a4@(" #x ":L)" +#else +#define A4(x) #x +#endif /* SMALL_DATA */ + +/****************************************************************************/ + +asm(" + + .text + .even + + .globl _RexxSysBase + .globl __FreeSpace + +__FreeSpace: + + moveal sp@(4),a0 + moveal sp@(8),a1 + movel sp@(12),d0 + movel a6,sp@- + moveal "A4(_RexxSysBase)",a6 + jsr a6@(-120) + moveal sp@+,a6 + rts + +"); + +/****************************************************************************/ + +asm(" + + .text + .even + + .globl _RexxSysBase + .globl __GetSpace + +__GetSpace: + + moveal sp@(4),a0 + movel sp@(8),d0 + movel a6,sp@- + moveal "A4(_RexxSysBase)",a6 + jsr a6@(-114) + moveal sp@+,a6 + rts + +"); + +/****************************************************************************/ + +asm(" + + .text + .even + + .globl _RexxSysBase + .globl __IsSymbol + +__IsSymbol: + moveal sp@(4),a0 + movel a6,sp@- + moveal "A4(_RexxSysBase)",a6 + jsr a6@(-102) + moveal sp@+,a6 + moveal sp@(8),a1 + movel d1,a1@ + rts + +"); + +/****************************************************************************/ + +asm(" + + .text + .even + + .globl _RexxSysBase + .globl __CurrentEnv + +__CurrentEnv: + moveal sp@(4),a0 + movel a6,sp@- + moveal "A4(_RexxSysBase)",a6 + jsr a6@(-108) + moveal sp@+,a6 + moveal sp@(8),a1 + movel a0,a1@ + rts + +"); + +/****************************************************************************/ + +asm(" + + .text + .even + + .globl _RexxSysBase + .globl __FetchValue + +__FetchValue: + moveal sp@(4),a0 + moveal sp@(8),a1 + movel sp@(12),d0 + movel sp@(16),d1 + movel a6,sp@- + moveal "A4(_RexxSysBase)",a6 + jsr a6@(-72) + moveal sp@+,a6 + moveal sp@(20),a1 + movel a0,a1@ + moveal sp@(24),a1 + movel d1,a1@ + rts + +"); + +/****************************************************************************/ + +asm(" + + .text + .even + + .globl _RexxSysBase + .globl __EnterSymbol + +__EnterSymbol: + moveal sp@(4),a0 + moveal sp@(8),a1 + movel sp@(12),d0 + movel a6,sp@- + moveal "A4(_RexxSysBase)",a6 + jsr a6@(-66) + moveal sp@+,a6 + rts + +"); + +/****************************************************************************/ + +asm(" + + .text + .even + + .globl _RexxSysBase + .globl __FreeSpace + +__SetValue: + moveal sp@(4),a0 + moveal sp@(8),a1 + movel sp@(12),d0 + movel a6,sp@- + moveal "A4(_RexxSysBase)",a6 + jsr a6@(-84) + moveal sp@+,a6 + rts + +"); + +/****************************************************************************/ + +asm(" + + .text + .even + + .globl _RexxSysBase + .globl __FreeSpace + +__StrcpyN: + moveal sp@(4),a0 + moveal sp@(8),a1 + movel sp@(12),d0 + movel a6,sp@- + moveal "A4(_RexxSysBase)",a6 + jsr a6@(-270) + moveal sp@+,a6 + moveal sp@(16),a1 + movel d1,a1@ + rts + +"); + +/****************************************************************************/ + +#endif /* __GNUC__ && !__amigaos4__ */ + +/****************************************************************************/ + +/* Function prototypes for the 68k stubs. */ +extern VOID _FreeSpace(struct Environment * env,APTR mem,LONG size); +extern APTR _GetSpace(struct Environment * env,LONG size); +extern LONG _IsSymbol(STRPTR name,LONG * symbol_length_ptr); +extern VOID _CurrentEnv(struct RexxTask *task,struct Environment ** environment_ptr); +extern struct Node * _FetchValue(struct Environment * env,struct NexxStr * stem,struct NexxStr * compound,struct Node *symbol_table_node,LONG * is_literal_ptr,struct NexxStr ** value_ptr); +extern struct Node * _EnterSymbol(struct Environment * env,struct NexxStr * stem,struct NexxStr * compound); +extern VOID _SetValue(struct Environment * env,struct NexxStr * value,struct Node * symbol_table_node); +extern ULONG _StrcpyN(STRPTR destination,STRPTR source,LONG length); + +/****************************************************************************/ + +/* Releases a string structure, if it's not owned at the time. */ +STATIC VOID +FreeString(struct Environment * environment,struct NexxStr * ns) +{ + /* Not currently owned? */ + if(!(ns->ns_Flags & NSF_KEEP)) + _FreeSpace(environment,ns,sizeof(*ns) + ns->ns_Length + 1); /* struct Environment * a0,APTR block a1,LONG d0 */ +} + +/****************************************************************************/ + +/* Allocates and initializes a string structure. */ +STATIC struct NexxStr * +MakeString(struct Environment * environment,STRPTR value,LONG length) +{ + struct NexxStr * result = NULL; + struct NexxStr * ns; + + /* Allocate memory for the NexxStr and the NUL-terminated string itself. */ + ns = _GetSpace(environment,sizeof(*ns) + length + 1); /* struct Environment * a0,LONG d0 : APTR d0 */ + if(ns == NULL) + goto out; + + /* Fill in the NexxStr structure, copy the string and remember the hash value for it. */ + ns->ns_Length = length; + ns->ns_Flags = NSF_STRING; + ns->ns_Hash = _StrcpyN((STRPTR)ns->ns_Buff,value,length); /* STRPTR a0,STRPTR a1,LONG d0 : ULONG d0 */ + + result = ns; + +out: + + return(result); +} + +/****************************************************************************/ + +/* Classifies a symbol and returns the stem and compound parts. */ +STATIC LONG +TypeString(STRPTR variable_name,struct Environment * environment,struct NexxStr ** compound_ptr,struct NexxStr ** stem_ptr) +{ + struct NexxStr * compound; + struct NexxStr * stem = NULL; + LONG error = ERR10_003; /* no memory available */ + LONG stem_length; + LONG symbol_length; + STRPTR dot; + + (*compound_ptr) = NULL; + (*stem_ptr) = NULL; + + /* The 'compound' part is the entire variable name, including all dots and + what's in between them. */ + compound = MakeString(environment,variable_name,strlen(variable_name)); + if(compound == NULL) + goto out; + + /* Find the first dot in the variable name. Everything in front of it + constitutes the 'stem' part. If there is no dot in the name, then + the 'compound' and 'stem' parts are identical. */ + dot = memchr(compound->ns_Buff,'.',compound->ns_Length); + if(dot != NULL) + stem_length = ((char *)dot - (char *)compound->ns_Buff) + 1; + else + stem_length = compound->ns_Length; + + /* Make a copy of the 'stem' part. */ + stem = MakeString(environment,variable_name,stem_length); + if(stem == NULL) + goto out; + + /* Figure out if this is a symbol after all. */ + _IsSymbol((STRPTR)stem->ns_Buff,&symbol_length); /* STRPTR a0 : LONG d0, LONG d1 */ + + /* The entire name must match the stem part. */ + if(symbol_length != stem->ns_Length) + { + error = ERR10_040; /* invalid variable name */ + goto out; + } + + (*compound_ptr) = compound; + (*stem_ptr) = stem; + + error = 0; + +out: + + if(error != 0) + { + if(compound != NULL) + FreeString(environment,compound); + + if(stem != NULL) + FreeString(environment,stem); + } + + return(error); +} + +/****************************************************************************/ + +/* Retrieves the value of a variable from the current storage environment. */ +LONG +GetRexxVar(struct RexxMsg *context,STRPTR variable_name,STRPTR * return_value) +{ + struct Environment * environment; + struct NexxStr * ns; + struct NexxStr * compound_string; + struct NexxStr * stem_string; + LONG is_literal; + LONG error; + + (*return_value) = NULL; + + if(!CheckRexxMsg(context)) + { + error = ERR10_010; /* invalid message packet */ + goto out; + } + + /* Find the current storage environment. */ + _CurrentEnv(context->rm_TaskBlock,&environment); /* struct RexxTask * a0 : struct Environment * a0 */ + + /* Create the stem and component parts. */ + error = TypeString(variable_name,environment,&compound_string,&stem_string); + if(error != 0) + goto out; + + /* Look up the value. NOTE: _FetchValue() will free the two 'struct NexxStr *' provided. */ + _FetchValue(environment,stem_string,compound_string,NULL,&is_literal,&ns); /* struct Environment * a0,struct NexxStr * a1,struct NexxStr * d0,struct Node * d1 : struct NexxStr * a0, LONG d1 */ + + /* If this is not a literal, return a pointer to the string. */ + if(!is_literal) + (*return_value) = (STRPTR)ns->ns_Buff; + + error = 0; + +out: + + return(error); +} + +/****************************************************************************/ + +/* Assigns a value to a variable in the current storage environment. */ +LONG +SetRexxVar(struct RexxMsg *context,STRPTR variable_name,STRPTR value,LONG length) +{ + struct Environment * environment; + struct NexxStr * compound_string; + struct NexxStr * stem_string; + struct Node * symbol_table_node; + struct NexxStr *value_string; + LONG error; + + /* Make sure the value string is not too long */ + if(length > 65535) + { + error = ERR10_009; /* symbol or string too long */ + goto out; + } + + if(!CheckRexxMsg(context)) + { + error = ERR10_010; /* invalid message packet */ + goto out; + } + + /* Find the current storage environment. */ + _CurrentEnv(context->rm_TaskBlock,&environment); /* struct RexxTask * a0 : struct Environment * a0 */ + + /* Create the stem and compound parts */ + error = TypeString(variable_name,environment,&compound_string,&stem_string); + if(error != 0) + goto out; + + /* Locate or create the symbol node. NOTE: _EnterSymbol() will put the two 'struct NexxStr *' into + the symbol table. It is not nececessary to free them. */ + symbol_table_node = _EnterSymbol(environment,stem_string,compound_string); /* struct Environment a0, struct NexxStr *a1, struct NexxStr * d0 : struct Node * d0 */ + if(symbol_table_node == NULL) + { + error = ERR10_003; /* no memory available */ + goto out; + } + + /* Create the value string. */ + value_string = MakeString(environment,value,length); + if(value_string == NULL) + { + error = ERR10_003; /* no memory available */ + goto out; + } + + /* Install the value string. */ + _SetValue(environment,value_string,symbol_table_node); /* struct Environment *a0, struct NexxStr *a1, struct Node * d0 */ + + error = 0; + +out: + + return(error); +} + +/****************************************************************************/ + +#endif diff --git a/library/changes b/library/changes index 4864d26..8d45ac8 100644 --- a/library/changes +++ b/library/changes @@ -1,3 +1,8 @@ +- Rewrote the GetRexxVar()/SetRexxVar() functions (mostly) in 'C', using available + code as a reference. The 68k stubs currently only work for the 68k version of + the library, and a solution for the OS4 build still needs to be found. The code + is currently untested, but it should be complete. + - The printf() family now ignores argument specifications, as in "%2$d %1$d", which are used for localization on some platforms. This is a non-standard feature and the way clib2 treats it for now is just intended to avoid