home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * IPC.C 25 September 1988
- *
- * NOTE! the BSS segment is not initialized to 0.
- */
-
- #include <local/typedefs.h>
- #include <local/ipc.h>
-
- extern EXECBASE *SysBase;
-
- static long IPCLock[2] = { 0, 0 };
- static MLIST IPCList = { (MNODE *)&IPCList.mlh_Tail, NULL, (MNODE *)&IPCList.mlh_Head };
-
- extern void *FindName();
- extern IPCMSG *lSendIPC2();
- extern char *CCall();
- extern APTR Duplicate();
-
- /*
- * Three-pass command parser.
- * (1) Determine # of arguments and allocate argv array, resolve variables
- * (2) Determine length of each argument and allocate entries in the array
- * (3) Fill entries in the array
- *
- * On return, an filled ARGV array will be returned. To free the argv
- * array and elements, call FreeParseCmd(argv). Individual argv[]
- * entries may be modified, including stuffing different pointers in,
- * without effecting FreeParseCmd(). Note that offset -1 in each entry
- * contains a status byte, currently only bit 0 (was quoted) is used.
- */
-
- lParseCmd(buf, pav, varget, varfree, error, reserved)
- char *buf;
- char ***pav;
- char *((*varget)());
- char *((*varfree)());
- long *error;
- {
- short numac; /* # of argv entries */
- char **av = NULL; /* argv array */
- long *arglen = NULL; /* array of entry lengths */
- MLIST VList; /* Hold $variable contents */
- char *endstrvar(); /* extracts variable name */
- short ttllen = 0; /* sum of lengths of entries */
-
- NewList(&VList);
- *error = 0;
-
- /*
- * PASS1, determine # of arguments and retrieve variables
- */
-
- {
- register char *ptr;
- register short ac = 0;
- register short quo = 0;
-
- for (ptr = buf; *ptr == ' ' || *ptr == 9; ++ptr);
- for (; *ptr; ++ptr) {
- switch(*ptr) {
- case '(':
- ++quo;
- break;
- case ')':
- --quo;
- break;
- case '\\':
- case '^':
- if (ptr[1])
- ++ptr;
- break;
- case ' ':
- case 9:
- if (!quo) {
- while (*ptr == ' ' || *ptr == 9)
- ++ptr;
- if (*ptr)
- ++ac;
- --ptr;
- }
- break;
- case '$':
- {
- short len;
- char tmp[64];
- char *str;
- MNODE *vl;
-
- ++ptr;
- str = endstrvar(ptr, &len);
- if (*ptr == '(')
- ++ptr;
- BMov(ptr, tmp, len);
- tmp[len] = 0;
- if (varget && (ptr = (char *)CCall(varget, tmp))) {
- vl = AllocMem(8 + strlen(ptr) + 1, MEMF_PUBLIC);
- if (!vl) {
- *error = (PERR_NOMEM << 16) | (ptr - buf);
- goto fail;
- }
- strcpy(vl+1, ptr);
- if (varfree)
- CCall(varfree, ptr);
- } else {
- *error = (PERR_NOVAR << 16) | (ptr - buf);
- goto fail;
- }
- AddTail(&VList, vl);
- ptr = str - 1;
- }
- break;
- }
- }
- ++ac;
- numac = ac;
- }
-
- /*
- * av[-1] = master string pointer (see below)
- * av[-2] = sizeof av array
- * av[ac] = NULL
- *
- * Pass 2, allocate argv array and storage for the lengths of each
- * entry. Determine the length of each entry.
- */
-
- av = AllocMem(sizeof(char *) * (numac + 3), MEMF_PUBLIC);
- if (!av) {
- *error = (PERR_NOMEM << 16);
- goto fail;
- }
- av += 2;
- av[-2] = (char *)(sizeof(char *) * (numac + 3));
- arglen = AllocMem(sizeof(long) * numac, MEMF_PUBLIC);
- if (!arglen) {
- *error = (PERR_NOMEM << 16);
- goto fail;
- }
-
- {
- register char *ptr;
- register short ac = 0;
- register short quo = 0;
- register short len = 0;
-
- for (ptr = buf; *ptr == ' ' || *ptr == 9; ++ptr);
- for (; *ptr; ++ptr) {
- switch(*ptr) {
- case '(':
- ++quo;
- if (quo != 1)
- ++len;
- break;
- case ')':
- --quo;
- if (quo)
- ++len;
- break;
- case '\\':
- case '^':
- if (ptr[1]) {
- ++ptr;
- ++len;
- }
- break;
- case ' ':
- case 9:
- if (!quo) {
- while (*ptr == ' ' || *ptr == 9)
- ++ptr;
- if (*ptr) {
- arglen[ac] = len;
- ttllen += len + 2;
- ++ac;
- len = 0;
- }
- --ptr;
- } else {
- ++len;
- }
- break;
- case '$':
- {
- register MNODE *node = RemHead(&VList);
- if (node) {
- len += strlen(node+1);
- AddTail(&VList, node);
- }
- ptr = endstrvar(ptr + 1, NULL) - 1;
- }
- break;
- case '\n':
- break;
- default:
- ++len;
- break;
- }
- }
- arglen[ac] = len;
- ttllen += len + 2; /* 1 byte status & 1 byte separator */
- ++ac;
- }
- { /* allocate space for entries */
- register short i;
- register char *mem = AllocMem(4+ttllen, MEMF_PUBLIC);
- register char *ptr = mem + 4;
-
- if (!mem) {
- *error = (PERR_NOMEM << 16);
- goto fail;
- }
-
- *(long *)mem = 4 + ttllen;
- for (i = 0; i < numac; ++i) {
- *ptr++ = 0; /* status byte */
- av[i] = ptr;
- ptr[arglen[i]] = 0;
- ptr += arglen[i] + 1;
- }
- av[-1] = mem;
- }
- {
- register char *ptr;
- register char *avs = av[0];
- register short ac = 0;
- short quo = 0;
-
- for (ptr = buf; *ptr == ' ' || *ptr == 9; ++ptr);
- for (; *ptr; ++ptr) {
- switch(*ptr) {
- case '\\':
- if (ptr[1])
- *avs++ = *++ptr;
- break;
- case '^':
- if (ptr[1])
- *avs++ = *++ptr & 0x1F;
- break;
- case '(':
- ++quo;
- if (quo != 1)
- *avs++ = '(';
- else if (avs == av[ac]) /* quoted argument */
- avs[-1] = 1;
- break;
- case ')':
- --quo;
- if (quo) {
- *avs++ = ')';
- break;
- } /* fall through */
- case ' ':
- case 9:
- if (!quo) {
- ++ptr;
- while (*ptr == ' ' || *ptr == 9)
- ++ptr;
- if (*ptr) {
- *avs = 0;
- avs = av[++ac];
- }
- --ptr;
- } else {
- *avs++ = *ptr;
- }
- break;
- case '$':
- {
- register MNODE *node = RemHead(&VList);
- if (node) {
- strcpy(avs, node + 1);
- avs += strlen(avs);
- FreeMem(node, 8 + strlen(node+1) + 1);
- }
- ptr = endstrvar(ptr + 1, NULL) - 1;
- }
- break;
- case '\n':
- break;
- default:
- *avs++ = *ptr;
- break;
- }
- }
- *avs = 0;
- ++ac;
- }
- FreeMem(arglen, sizeof(long) * numac);
- *pav = av;
- av[numac] = NULL;
- return(numac);
-
- fail:
- {
- register MNODE *node;
-
- if (arglen)
- FreeMem(arglen, sizeof(long) * numac);
- if (av)
- FreeMem(av - 2, (long)av[-2]);
- while (node = RemHead(&VList))
- FreeMem(node, 8 + strlen(node+1) + 1);
- }
- *pav = NULL;
- return(0);
- }
-
- lFreeParseCmd(av)
- char **av;
- {
- FreeMem(av[-1], *(long *)av[-1]);
- FreeMem(av - 2, (long)av[-2]);
- }
-
- char *
- endstrvar(ptr, plen)
- short *plen;
- register char *ptr;
- {
- register short len = 0;
- if (*ptr == '(') {
- ++ptr;
- while (*ptr && *ptr != ')') {
- ++ptr;
- ++len;
- }
- if (*ptr == ')')
- ++ptr;
- } else {
- while ((*ptr >= 'a' && *ptr <= 'z') ||
- (*ptr >= 'A' && *ptr <= 'Z') ||
- (*ptr >= '0' && *ptr <= '9') ||
- (*ptr == '_')) {
- ++len;
- ++ptr;
- }
- }
- if (len > 62)
- len = 62;
- if (plen)
- *plen = len;
- return(ptr);
- }
-
- IPCPORT *
- lOpenIPC(name, flags)
- char *name;
- {
- register IPCPORT *port;
- register char *ptr;
-
- port = AllocMem(sizeof(IPCPORT), MEMF_PUBLIC|MEMF_CLEAR);
- if (!port)
- goto fail;
- ptr = AllocMem(strlen(name)+1, MEMF_PUBLIC);
- if (!ptr)
- goto fail;
- strcpy(ptr, name);
- port->Flags = flags;
- port->Port.mp_Node.ln_Type = NT_MSGPORT;
- port->Port.mp_Node.ln_Name = ptr;
- port->Port.mp_Flags = PA_SIGNAL;
- port->Port.mp_SigBit = AllocSignal(-1);
- port->Port.mp_SigTask = FindTask(NULL);
- NewList(&port->Port.mp_MsgList);
-
- LockAddr(IPCLock);
- Insert(&IPCList, port, FindName(&IPCList, name));
- UnLockAddr(IPCLock);
- return(port);
- fail:
- if (port) {
- FreeMem(port, sizeof(IPCPORT));
- if (ptr)
- FreeMem(ptr, strlen(ptr)+1);
- }
- return(NULL);
- }
-
- void
- lCloseIPC(port)
- register IPCPORT *port;
- {
- register IPCMSG *msg;
-
- LockAddr(IPCLock); /* remove port (no new messages) */
- Remove(port);
- UnLockAddr(IPCLock);
- while (msg = GetMsg(port)) /* reply to pending msgs w/error */
- ReplyIPC(msg, NULL, 0, IF_NOTFND);
- FreeMem(port->Port.mp_Node.ln_Name, strlen(port->Port.mp_Node.ln_Name)+1);
- if (port->Port.mp_Flags == PA_SIGNAL)
- FreeSignal(port->Port.mp_SigBit);
- FreeMem(port, sizeof(IPCPORT));
- }
-
- /*
- * msg = SendIPC(appname, buf, len, flags)
- */
-
- IPCMSG *
- lSendIPC(name, buf, len, flags)
- char *name;
- APTR buf;
- register long len, flags;
- {
- register IPCMSG *msg;
- register PORT *rport;
-
- msg = AllocMem(sizeof(IPCMSG)+sizeof(PORT), MEMF_PUBLIC|MEMF_CLEAR);
- if (msg == NULL)
- return(NULL);
- flags |= IF_ALLOCMSG; /* auto-deallocate later on */
- rport = (PORT *)(msg + 1);
- if (buf && !(flags & IF_NOCOPY) && !(flags & IF_ALLOC)) {
- if (!(buf = Duplicate(buf, len))) {
- FreeMem(msg, sizeof(IPCMSG)+sizeof(PORT));
- return(NULL);
- }
- flags |= IF_ALLOC;
- }
- rport->mp_Node.ln_Type = NT_MSGPORT;
- rport->mp_Flags = PA_SIGNAL;
- rport->mp_SigBit = 4;
- rport->mp_SigTask = SysBase->ThisTask;
- NewList(&rport->mp_MsgList);
-
- msg->Msg.mn_ReplyPort = rport;
- msg->Msg.mn_Length = sizeof(IPCMSG) + sizeof(PORT);
- msg->TBuf = buf;
- msg->TLen = len;
- msg->TFlags = flags;
- return(lSendIPC2(name, msg));
- }
-
- IPCMSG *
- lSendIPC2(name, msg)
- char *name;
- register IPCMSG *msg;
- {
- register IPCPORT *port;
-
- msg->RBuf = NULL;
- msg->RLen = 0;
- msg->RFlags = 0;
- msg->Error = 0;
- msg->Confirm = NULL;
-
- LockAddr(IPCLock);
- if (name) {
- port = (IPCPORT *)FindName(&IPCList, name);
- } else {
- port = GetHead(&IPCList);
- }
- msg->ToPort = port;
- if (port) {
- if ((port->Flags & IF_ALLOC) && !(msg->TFlags & IF_ALLOC)) {
- if ((msg->TBuf = Duplicate(msg->TBuf, msg->TLen)) == NULL) {
- msg->Error = PERR_NOMEM;
- lReplyIPC(msg, NULL, 0, IF_ERROR);
- return(msg);
- }
- msg->TFlags |= IF_ALLOC;
- }
- PutMsg(port, msg);
- UnLockAddr(IPCLock);
- } else {
- UnLockAddr(IPCLock);
- lReplyIPC(msg, NULL, 0, IF_ERROR|IF_NOTFND|IF_NOAPP);
- }
- return(msg);
- }
-
- /*
- * DoIPC2(name, msg, collfunc, collport)
- *
- * Synchronous IPC routine. To prevent lockouts in case the calling task
- * also owns an IPC port, if this port is provided 'collfunc' will
- * automatically be called if new requests arrive while we are waiting
- * for our request to complete. This call is reentrant.
- */
-
- void
- lDoIPC2(name, msg, func, port)
- char *name;
- IPCMSG *msg;
- void (*func)();
- PORT *port;
- {
- SendIPC2(name, msg); /* send the message */
- if (port) {
- register long mask1 = 1 << port->mp_SigBit;
- register long mask2 = 1 << msg->Msg.mn_ReplyPort->mp_SigBit;
-
- while (!CheckMsg(msg)) {
- if (CheckPort(port)) {
- CCall(func, port);
- continue;
- }
- Wait(mask1 | mask2);
- }
- }
- WaitMsg(msg);
- }
-
- /*
- * (void )ReplyIPC(msg, buf, len, flags)
- */
-
- lReplyIPC(msg, buf, len, flags)
- register IPCMSG *msg;
- APTR buf;
- long len, flags;
- {
- if (buf && !(flags & (IF_NOCOPY|IF_ALLOC|IF_NOTFND))) {
- buf = Duplicate(buf, len);
- flags |= IF_ALLOC;
- }
- if (buf || !(flags & IF_NOTFND)) {
- if ((msg->RFlags & IF_ALLOC) && msg->RBuf && buf != msg->RBuf)
- FreeMem(msg->RBuf, msg->RLen);
- msg->RBuf = buf;
- msg->RLen = len;
- }
- msg->RFlags = flags;
- LockAddr(IPCLock);
- if (msg->RFlags & IF_GLOBAL) {
- register IPCPORT *next;
-
- do {
- next = GetSucc(next);
- } while (next && !(next->Flags & IF_GLOBAL));
- if (next) {
- msg->ToPort = next;
- PutMsg(next, msg);
- } else {
- if ((msg->TFlags & IF_ALLOC) && msg->TBuf) {
- FreeMem(msg->TBuf, msg->TLen);
- msg->TBuf = NULL;
- }
- ReplyMsg(msg);
- }
- UnLockAddr(IPCLock);
- return;
- }
- if (flags & IF_NOTFND) {
- register IPCPORT *next = GetSucc(msg->ToPort);
- if (next && strcmp(msg->ToPort->Port.mp_Node.ln_Name, next->Port.mp_Node.ln_Name) == 0) {
- msg->ToPort = next;
- PutMsg(next, msg);
- } else {
- if ((msg->TFlags & IF_ALLOC) && msg->TBuf) {
- FreeMem(msg->TBuf, msg->TLen);
- msg->TBuf = NULL;
- }
- ReplyMsg(msg);
- msg->RFlags |= IF_ERROR;
- }
- UnLockAddr(IPCLock);
- return;
- }
- UnLockAddr(IPCLock);
- if ((msg->TFlags & IF_ALLOC) && msg->TBuf) {
- FreeMem(msg->TBuf, msg->TLen);
- msg->TBuf = NULL;
- }
- ReplyMsg(msg);
- return;
- }
-
- /*
- * (void) lFreeIPC(msg)
- *
- * Free space associated with the reply buffer and possibly the message
- * itself. This call MUST be made after you receive a reply to your
- * message.
- */
-
- void
- lFreeIPC(msg)
- register IPCMSG *msg;
- {
- if ((msg->RFlags & IF_ALLOC) && msg->RBuf) {
- FreeMem(msg->RBuf, msg->RLen);
- msg->RBuf = NULL;
- }
- if (msg->Confirm) /* Confirmation requested */
- CCall(msg->Confirm, msg);
- if (msg->TFlags & IF_ALLOCMSG) /* Message was allocated */
- FreeMem(msg, msg->Msg.mn_Length);
- }
-
- APTR
- Duplicate(buf, len)
- APTR buf;
- long len;
- {
- APTR newbuf;
- if (newbuf = AllocMem(len, TypeOfMem(buf))) {
- BMov(buf, newbuf, len);
- return(newbuf);
- }
- return(NULL);
- }
-
- #asm
-
- ; CCall(funcptr, argument)
-
- _CCall: movem.l 4(sp),A0/A1
- movem.l D2/D3/A4/A5/A6,-(sp)
- move.l A1,-(sp)
- jsr (A0)
- addq.l #4,sp
- movem.l (sp)+,D2/D3/A4/A5/A6
- rts
- #endasm
-
-