/* $Revision Header * Header built automatically - do not edit! ************* * * (C) Copyright 1990 by MXM * * Name .....: RexxHostLib.c * Created ..: Sunday 07-Jan-90 18:55 * Revision .: 14 * * Date Author Comment * ========= ======== ==================== * 09-Sep-90 Olsen Bug fixed in GetToken, added * IsSpace() and GetRexxClip() * 24-May-90 Olsen General rewrite, added new functions * 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 14 /* Main rexx library base. */ extern struct RxsLib *RexxSysBase; /* 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; /* Valid name given? */ if(HostName && HostName[0]) { /* Already present? */ if(!FindPort((char *)HostName)) { /* Allocate the port body. */ if(RexxHost = (struct RexxHost *)AllocMem(sizeof(struct RexxHost),MEMF_PUBLIC | MEMF_CLEAR)) { /* Allocate a signal bit. */ if((RexxHost -> rh_Port . mp_SigBit = AllocSignal(-1)) != -1) { /* 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)) { /* 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_SigTask = SysBase -> ThisTask; /* A dummy ID. */ RexxHost -> rh_SpecialID = 'REXX'; /* Finally add it to the public port list. */ AddPort(&RexxHost -> rh_Port); /* And return it to the caller. */ return(RexxHost); } FreeSignal(RexxHost -> rh_Port . mp_SigBit); } FreeMem(RexxHost,sizeof(struct RexxHost)); } } } return(NULL); } /* 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; /* Valid host port given? */ if(RexxHost && RexxHost -> rh_SpecialID == 'REXX') { /* Remove it from the public list. */ RemPort(&RexxHost -> rh_Port); /* 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) { /* 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)) { /* Add the command. */ if(HostMessage -> rm_Args[0] = CreateArgstring((char *)CommandString,StrLen((char *)CommandString))) { /* This is a command, not a function. */ HostMessage -> rm_Action = RXCOMM; /* Release it... */ PutMsg(RexxPort,HostMessage); /* Successful action. */ return(TRUE); } DeleteRexxMsg(HostMessage); } } return(FALSE); } /* 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); } /* IsSpace(): * * Returns TRUE if the input character is a space, tab, * carriage return, newline, form feed or vertical tab. */ STATIC BYTE IsSpace(UBYTE c) { if((c >= 13 && c <= 17) || c == 32) return(TRUE); else return(FALSE); } /* 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; SHORT i,StrEnd = 0,MaxPos = StrLen((char *)String); /* Last counter position. */ if(MaxPos >= MaxLength + *StartChar) MaxPos = MaxLength + *StartChar - 1; /* Already finished with argument string? */ if(*StartChar <= StrLen((char *)String) - 1 && String && String[0] && AuxBuff && MaxLength) { /* Parse the argument string... */ for(i = *StartChar ; i <= MaxPos ; i++) { /* Skip leading blanks... */ if(!StrEnd && IsSpace(String[i])) { while(IsSpace(String[i]) && i < MaxPos) { i++; (*StartChar)++; } } /* Found an argument. */ if(IsSpace(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 Value; BYTE Sign = 1; SHORT i; /* Valid argument given? */ if(String && !String[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); } return(0); } /* 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; SHORT i = 0,j; LONG Sign; UBYTE c; /* Valid argument given? */ if(String) { /* 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; } } return(String); } /* AmigaToUpper(c): * * Replacement for toupper() macro, also knows how to * map international characters to uppercase. Note: not * a real library module. */ STATIC UBYTE AmigaToUpper(UBYTE 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)); } /* GetRexxMsg(): * * Picks up pending RexxMessages from a RexxHost and * returns them to the caller. I desired, will wait * for new messages to arrive if none is present yet. */ struct RexxMsg * GetRexxMsg(struct RexxHost *RexxHost,LONG Wait) { struct RexxHostBase *RexxHostBase; struct RexxMsg *RexxMessage = NULL; /* Valid pointer given? */ if(RexxHost && RexxHost -> rh_SpecialID == 'REXX') { /* Try to pick up a message. */ while(!(RexxMessage = (struct RexxMsg *)GetMsg((struct MsgPort *)RexxHost))) { /* No message available. Are we to wait? */ if(Wait) WaitPort((struct MsgPort *)RexxHost); else break; } } /* Return the result (may be NULL). */ return(RexxMessage); } /* SendRexxMsg(): * * Sends a single (or a list of) command(s) to Rexx host * and returns the secondary result. */ ULONG SendRexxMsg(STRPTR HostName,STRPTR *MsgList,STRPTR SingleMsg,LONG GetResult) { struct RexxHostBase *RexxHostBase; struct RexxMsg *RexxMessage; struct MsgPort *HostPort,*ReplyPort; ULONG Result = 0; SHORT i; /* Valid pointers given? */ if(HostName && (MsgList || SingleMsg)) { /* Can we find the host? */ if(HostPort = (struct MsgPort *)FindPort((char *)HostName)) { /* Allocate a reply port. */ if(ReplyPort = (struct MsgPort *)AllocMem(sizeof(struct MsgPort),MEMF_PUBLIC | MEMF_CLEAR)) { if((ReplyPort -> mp_SigBit = AllocSignal(-1)) != -1) { ReplyPort -> mp_Node . ln_Type = NT_MSGPORT; ReplyPort -> mp_Flags = PA_SIGNAL; ReplyPort -> mp_SigTask = SysBase -> ThisTask; InitList(&ReplyPort -> mp_MsgList); /* Create a Rexx message. */ if(RexxMessage = (struct RexxMsg *)CreateRexxMsg(ReplyPort,"",(char *)HostName)) { /* A list of arguments or only a single arg? */ if(MsgList) { for(i = 0 ; i < 16 ; i++) RexxMessage -> rm_Args[i] = MsgList[i]; } else RexxMessage -> rm_Args[0] = SingleMsg; /* Do we want result codes? */ if(GetResult) RexxMessage -> rm_Action = RXFF_RESULT; /* Send packet and wait for the reply. */ PutMsg(HostPort,RexxMessage); WaitPort(ReplyPort); /* Remember result. */ if(GetResult && !RexxMessage -> rm_Result1) Result = RexxMessage -> rm_Result2; /* Remove Rexx message. */ DeleteRexxMsg(RexxMessage); } /* Free reply port signal bit. */ FreeSignal(ReplyPort -> mp_SigBit); } /* Free the replyport itself. */ FreeMem(ReplyPort,sizeof(struct MsgPort)); } } } /* Return the result. */ return(Result); } /* GetRexxString(): * * Copy the result string returned by SendRexxMsg to user * buffer and/or remove the original string. */ VOID GetRexxString(STRPTR SourceString,STRPTR DestString) { struct RexxHostBase *RexxHostBase; /* Valid pointer given? */ if(SourceString) { /* Destination memory buffer given? */ if(DestString) StrCpy((char *)DestString,(char *)SourceString); /* Deallocate the original string. */ DeleteArgstring((char *)SourceString); } } /* GetRexxClip(): * * Searches the rexx clip list for a node with given * name. */ LONG GetRexxClip(char *Name,LONG WhichArg) { struct RexxHostBase *RexxHostBase; /* Do we have valid buffers and size? */ if(Name && Name[0]) { struct RexxRsrc *Node; /* Can we find the clip node? */ if(Node = (struct RexxRsrc *)FindRsrcNode(&RexxSysBase -> rl_ClipList,Name,RRT_CLIP)) { if(WhichArg) return(Node -> rr_Arg1); else return(Node -> rr_Arg2); } } return(NULL); }