/* $Revision Header * Header built automatically - do not edit! ************* * * (C) Copyright 1990 by MXM * * Name .....: RexxHostLib.c * Created ..: Sunday 07-Jan-90 18:55 * Revision .: 12 * * Date Author Comment * ========= ======== ==================== * 26-Apr-90 Olsen Supports short integers (16 bits) * 13-Apr-90 Olsen Added assembly language routines * 31-Mar-90 Olsen Rewrote RexxStrCmp * 19-Mar-90 Olsen More sanity checks * 17-Mar-90 Olsen Added RexxStrCmp, rewrote * CreateRexxHost/DeleteRexxHost, * ANSIfication * 16-Mar-90 Olsen Rework for Aztec 5.0 release * 07-Jan-90 Olsen Added string conversion functions * 07-Jan-90 Olsen Added GetToken * 07-Jan-90 Olsen - Empty log message - * 07-Jan-90 Olsen Removed bug in SendRexxCommand * 07-Jan-90 Olsen - Empty log message - * 07-Jan-90 Olsen Created this file! * **************************************************************************** * * This Amiga shared library is based on example source code * written by Gary Samad & Bill Hawes. * * $Revision Header ********************************************************/ #define REVISION 12 /* The protos. */ struct RexxMsg *CreateRexxMsg(struct MsgPort *,char *,char *); STRPTR CreateArgstring(char *,LONG); VOID DeleteRexxMsg(struct RexxMsg *); VOID DeleteArgstring(char *); STATIC LONG AmigaToUpper(LONG); /* The magic pragma. */ #pragma regcall(AmigaToUpper(d0)) /* Bill Hawes didn't distribute an .fd file along * with the 1.10 release of ARexx. I had to put these * pragmas together by hand. */ #pragma amicall(RexxSysBase, 0x90, CreateRexxMsg(a0,a1,d0)) #pragma amicall(RexxSysBase, 0x7e, CreateArgstring(a0,d0)) #pragma amicall(RexxSysBase, 0x96, DeleteRexxMsg(a0)) #pragma amicall(RexxSysBase, 0x84, DeleteArgstring(a0)) /* Global revision identifier. */ LONG Revision = REVISION; /* CreateRexxHost(HostName): * * Creates a RexxHost (special MsgPort) with a given name. * Returns NULL if port already exists. */ struct RexxHost * CreateRexxHost(STRPTR HostName) { struct RexxHostBase *RexxHostBase; struct RexxHost *RexxHost = NULL; /* Our pointer to ExecBase. */ extern struct ExecBase *SysBase; if(HostName && HostName[0]) { /* Already present? */ if(!FindPort((char *)HostName)) { LONG SigBit; /* Allocate a signal bit. */ if((SigBit = AllocSignal(-1)) == -1) goto Quit; /* Allocate the port body. */ if(!(RexxHost = (struct RexxHost *)AllocMem(sizeof(struct RexxHost),MEMF_PUBLIC | MEMF_CLEAR))) { FreeSignal(SigBit); goto Quit; } /* Initialize the MsgPort node head. */ RexxHost -> rh_Port . mp_Node . ln_Type = NT_MSGPORT; RexxHost -> rh_Port . mp_Node . ln_Pri = 1; /* Allocate memory for MsgPort name. */ if(!(RexxHost -> rh_Port . mp_Node . ln_Name = (char *)AllocMem(StrLen((char *)HostName) + 1,MEMF_PUBLIC))) { FreeMem(RexxHost,sizeof(struct RexxHost)); FreeSignal(SigBit); RexxHost = NULL; goto Quit; } /* Copy the name. */ StrCpy(RexxHost -> rh_Port . mp_Node . ln_Name,(char *)HostName); /* Deal with the rest of the flags. */ RexxHost -> rh_Port . mp_Flags = PA_SIGNAL; RexxHost -> rh_Port . mp_SigBit = SigBit; RexxHost -> rh_Port . mp_SigTask = SysBase -> ThisTask; /* A dummy ID. */ RexxHost -> rh_SpecialID = 'REXX'; /* Finally add it to the public port list. */ AddPort(&RexxHost -> rh_Port); } } Quit: return(RexxHost); } /* DeleteRexxHost(RexxHost): * * Deletes a MsgPort as created by CreateRexxHost(). * Returns NULL, so user can do 'Host = DeleteRexxHost(Host);'. */ VOID * DeleteRexxHost(struct RexxHost *RexxHost) { struct RexxHostBase *RexxHostBase; if(RexxHost && RexxHost -> rh_SpecialID == 'REXX') { /* Remove it from the public list. */ RemPort(&RexxHost -> rh_Port); /* Make it difficult to reuse it by accident. */ RexxHost -> rh_Port . mp_Node . ln_Type = 0xFF; RexxHost -> rh_Port . mp_MsgList . lh_Head = (struct Node *)-1; /* Free the name. */ FreeMem(RexxHost -> rh_Port . mp_Node . ln_Name,StrLen(RexxHost -> rh_Port . mp_Node . ln_Name) + 1); /* Free the allocated signal bit. */ FreeSignal(RexxHost -> rh_Port . mp_SigBit); /* Free the body. */ FreeMem(RexxHost,sizeof(struct RexxHost)); } return(NULL); } /* SendRexxCommand(HostPort,CommandString,FileExtension,HostName): * * Sends a command to the rexx server, requires pointers * to the MsgPort of the calling Host and the command string. * File extension and host name are optional and may be * NULL. */ LONG SendRexxCommand(struct RexxHost *HostPort,STRPTR CommandString,STRPTR FileExtension,STRPTR HostName) { struct RexxHostBase *RexxHostBase; struct MsgPort *RexxPort = (struct MsgPort *)FindPort(RXSDIR); struct RexxMsg *HostMessage; /* Valid pointers given? */ if(!CommandString || !HostPort || HostPort -> rh_SpecialID != 'REXX' || !RexxPort) return(FALSE); /* No special host name given? Take the MsgPort name. */ if(!HostName) HostName = (STRPTR)HostPort -> rh_Port . mp_Node . ln_Name; /* No file name extension? Take the default. */ if(!FileExtension) FileExtension = (STRPTR)"rexx"; /* Create the message. */ if(!(HostMessage = CreateRexxMsg((struct MsgPort *)HostPort,(char *)FileExtension,(char *)HostName))) return(FALSE); /* Add the command. */ if(!(HostMessage -> rm_Args[0] = CreateArgstring((char *)CommandString,StrLen((char *)CommandString)))) { DeleteRexxMsg(HostMessage); return(FALSE); } /* This is a command, not a function. */ HostMessage -> rm_Action = RXCOMM; /* Release it... */ PutMsg(RexxPort,HostMessage); /* Successful action. */ return(TRUE); } /* FreeRexxCommand(RexxMessage): * * Frees the contents of a RexxMsg. */ VOID FreeRexxCommand(struct RexxMsg *RexxMessage) { struct RexxHostBase *RexxHostBase; /* Valid pointer given? */ if(RexxMessage && RexxMessage -> rm_Node . mn_Node . ln_Type == NT_REPLYMSG) { /* Remove argument. */ if(RexxMessage -> rm_Args[0]) DeleteArgstring((char *)RexxMessage -> rm_Args[0]); /* Free the message. */ DeleteRexxMsg(RexxMessage); } } /* ReplyRexxCommand(RexxMessage,Primary,Secondary,Result): * * Sends a RexxMsg back to the rexx server, can include * result codes. */ VOID ReplyRexxCommand(struct RexxMsg *RexxMessage,LONG Primary,LONG Secondary,STRPTR Result) { struct RexxHostBase *RexxHostBase; /* Valid pointer given? */ if(RexxMessage && RexxMessage -> rm_Node . mn_Node . ln_Type == NT_MESSAGE) { /* No secondary result and results wanted? */ if(Secondary == NULL && (RexxMessage -> rm_Action & RXFF_RESULT)) { /* Build result string... */ if(Result) Secondary = (LONG)CreateArgstring((char *)Result,StrLen((char *)Result)); } /* Set both results... */ RexxMessage -> rm_Result1 = Primary; RexxMessage -> rm_Result2 = Secondary; /* ...and reply the message. */ ReplyMsg(RexxMessage); } } /* GetRexxCommand(RexxMessage): * * Returns a pointer to the command string if * the RexxMsg is a command request. */ STRPTR GetRexxCommand(struct RexxMsg *RexxMessage) { struct RexxHostBase *RexxHostBase; if(!RexxMessage || RexxMessage -> rm_Node . mn_Node . ln_Type == NT_REPLYMSG) return(NULL); else return(RexxMessage -> rm_Args[0]); } /* GetRexxArg(RexxMessage): * * Returns a pointer to the first RexxMsg argument. */ STRPTR GetRexxArg(struct RexxMsg *RexxMessage) { struct RexxHostBase *RexxHostBase; if(!RexxMessage) return(NULL); else return(RexxMessage -> rm_Args[0]); } /* GetRexxResult1(RexxMessage): * * Returns the 1st RexxMsg result. */ LONG GetRexxResult1(struct RexxMsg *RexxMessage) { struct RexxHostBase *RexxHostBase; if(!RexxMessage) return(NULL); else return(RexxMessage -> rm_Result1); } /* GetRexxResult2(RexxMessage): * * Returns the 2nd RexxMsg result. */ LONG GetRexxResult2(struct RexxMsg *RexxMessage) { struct RexxHostBase *RexxHostBase; if(!RexxMessage) return(NULL); else return(RexxMessage -> rm_Result2); } /* GetToken(String,StartChar,AuxBuff,MaxLength): * * Fills a string with the next given string * argument. */ STRPTR GetToken(STRPTR String,LONG *StartChar,STRPTR AuxBuff,LONG MaxLength) { struct RexxHostBase *RexxHostBase; LONG i,StrEnd = 0,MaxPos = StrLen((char *)String); /* Last counter position. */ if(MaxPos >= MaxLength) MaxPos = MaxLength - 1; /* Already finished with argument string? */ if(*StartChar > StrLen((char *)String) - 1 || !String || !String[0] || !AuxBuff || !MaxLength) return(NULL); /* Parse the argument string... */ for(i = *StartChar ; i <= MaxPos ; i++) { /* Skip leading blanks... */ if(!StrEnd && String[i] == ' ') { while(String[i] == ' ' && i < MaxPos) { i++; (*StartChar)++; } } /* Found an argument. */ if(String[i] == ' ' || String[i] == 0) { /* Copy it to the auxiliary buffer. */ StrNCpy((char *)AuxBuff,(char *)(String + *StartChar),StrEnd); AuxBuff[StrEnd] = 0; /* Change the position counter (since * we can't use static data initialisation * calling program has to supply a * counter variable). */ (*StartChar) += StrEnd; return(AuxBuff); } /* Increment character counter. */ StrEnd++; } return(NULL); } /* GetStringValue(String): * * Returns the numeric value taken from given string * (just like atoi(), taken from example source code * by K&R). */ LONG GetStringValue(STRPTR String) { struct RexxHostBase *RexxHostBase; LONG i,Value,Sign = 1; /* Valid argument given? */ if(!String || !String[0]) return(0); /* Skip leading blank characters. */ for(i = 0 ; String[i] == ' ' || String[i] == '\n' || String[i] == '\t' ; i++); /* Remember sign extension. */ if(String[i] == '+' || String[i] == '-') Sign = (String[i++] == '+') ? 1 : -1; /* Convert from ASCII to decimal. */ for(Value = 0 ; String[i] >= '0' && String[i] <= '9' ; i++) Value = 10 * Value + String[i] - '0'; /* Return real value. */ return(Sign * Value); } /* BuildValueString(Value,String): * * Puts a numeric value in decimal form into a * given string (similar to itoa(), taken from * example source code by K&R). */ STRPTR BuildValueString(LONG Value,STRPTR String) { struct RexxHostBase *RexxHostBase; LONG i = 0,j,c,Sign; /* Valid argument given? */ if(!String) return(NULL); /* Remember sign extension. */ if((Sign = Value) < 0) Value = -Value; /* Convert it into ASCII characters (in * reverse order, i.e. 1234 = "4321"). */ do String[i++] = Value % 10 + '0'; while((Value /= 10) > 0); /* Add sign extension. */ if(Sign < 0) String[i++] = '-'; /* String NULL-termination. */ String[i] = 0; /* Reverse the string. */ for(i = 0, j = StrLen((char *)String) - 1 ; i < j ; i++, j--) { c = String[i]; String[i] = String[j]; String[j] = c; } /* Finished, return the string. */ return(String); } /* AmigaToUpper(c): * * Replacement for toupper() macro, also knows how to * map international characters to uppercase. Note: not * a real library module. */ STATIC LONG AmigaToUpper(LONG c) { /* -------- DEC --------- -------- ASCII ------- */ if((c >= 224 && c <= 254) || (c >= 'a' && c <= 'z')) c -= 32; return(c); } /* RexxStrCmp(Source,Target): * * Compares two strings ignoring case. */ LONG RexxStrCmp(STRPTR Source,STRPTR Target) { struct RexxHostBase *RexxHostBase; /* Do the string comparison ignoring case. */ for( ; AmigaToUpper(*Source) == AmigaToUpper(*Target) ; Source++, Target++) { if(!(*Source)) return(0); } return(AmigaToUpper(*Source) - AmigaToUpper(*Target)); }