home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 177.lha / DRes_v1.3 / src / ipc.c next >
Encoding:
C/C++ Source or Header  |  1988-04-28  |  12.6 KB  |  621 lines

  1.  
  2. /*
  3.  *  IPC.C   25 September 1988
  4.  *
  5.  *  NOTE!   the BSS segment is not initialized to 0.
  6.  */
  7.  
  8. #include <local/typedefs.h>
  9. #include <local/ipc.h>
  10.  
  11. extern EXECBASE *SysBase;
  12.  
  13. static long  IPCLock[2] = { 0, 0 };
  14. static MLIST IPCList = { (MNODE *)&IPCList.mlh_Tail, NULL, (MNODE *)&IPCList.mlh_Head };
  15.  
  16. extern void *FindName();
  17. extern IPCMSG *lSendIPC2();
  18. extern char *CCall();
  19. extern APTR Duplicate();
  20.  
  21. /*
  22.  *  Three-pass command parser.
  23.  *  (1) Determine # of arguments and allocate argv array, resolve variables
  24.  *  (2) Determine length of each argument and allocate entries in the array
  25.  *  (3) Fill entries in the array
  26.  *
  27.  *  On return, an filled ARGV array will be returned.  To free the argv
  28.  *  array and elements, call FreeParseCmd(argv).  Individual argv[]
  29.  *  entries may be modified, including stuffing different pointers in,
  30.  *  without effecting FreeParseCmd().  Note that offset -1 in each entry
  31.  *  contains a status byte, currently only bit 0 (was quoted) is used.
  32.  */
  33.  
  34. lParseCmd(buf, pav, varget, varfree, error, reserved)
  35. char *buf;
  36. char ***pav;
  37. char *((*varget)());
  38. char *((*varfree)());
  39. long *error;
  40. {
  41.     short numac;        /*    # of argv entries    */
  42.     char **av = NULL;        /*    argv array        */
  43.     long *arglen = NULL;    /*    array of entry lengths    */
  44.     MLIST VList;        /*    Hold $variable contents */
  45.     char *endstrvar();      /*  extracts variable name  */
  46.     short ttllen = 0;        /*    sum of lengths of entries   */
  47.  
  48.     NewList(&VList);
  49.     *error = 0;
  50.  
  51.     /*
  52.      *    PASS1, determine # of arguments and retrieve variables
  53.      */
  54.  
  55.     {
  56.     register char *ptr;
  57.     register short ac = 0;
  58.     register short quo = 0;
  59.  
  60.     for (ptr = buf; *ptr == ' ' || *ptr == 9; ++ptr);
  61.     for (; *ptr; ++ptr) {
  62.         switch(*ptr) {
  63.         case '(':
  64.         ++quo;
  65.         break;
  66.         case ')':
  67.         --quo;
  68.         break;
  69.         case '\\':
  70.         case '^':
  71.         if (ptr[1])
  72.             ++ptr;
  73.         break;
  74.         case ' ':
  75.         case 9:
  76.         if (!quo) {
  77.             while (*ptr == ' ' || *ptr == 9)
  78.             ++ptr;
  79.             if (*ptr)
  80.             ++ac;
  81.             --ptr;
  82.         }
  83.         break;
  84.         case '$':
  85.         {
  86.             short len;
  87.             char tmp[64];
  88.             char *str;
  89.             MNODE *vl;
  90.  
  91.             ++ptr;
  92.             str = endstrvar(ptr, &len);
  93.             if (*ptr == '(')
  94.             ++ptr;
  95.             BMov(ptr, tmp, len);
  96.             tmp[len] = 0;
  97.             if (varget && (ptr = (char *)CCall(varget, tmp))) {
  98.             vl = AllocMem(8 + strlen(ptr) + 1, MEMF_PUBLIC);
  99.             if (!vl) {
  100.                 *error = (PERR_NOMEM << 16) | (ptr - buf);
  101.                 goto fail;
  102.             }
  103.             strcpy(vl+1, ptr);
  104.             if (varfree)
  105.                 CCall(varfree, ptr);
  106.             } else {
  107.             *error = (PERR_NOVAR << 16) | (ptr - buf);
  108.             goto fail;
  109.             }
  110.             AddTail(&VList, vl);
  111.             ptr = str - 1;
  112.         }
  113.         break;
  114.         }
  115.     }
  116.     ++ac;
  117.     numac = ac;
  118.     }
  119.  
  120.     /*
  121.      *    av[-1]    = master string pointer (see below)
  122.      *    av[-2]    = sizeof av array
  123.      *    av[ac]    = NULL
  124.      *
  125.      *    Pass 2, allocate argv array and storage for the lengths of each
  126.      *        entry.    Determine the length of each entry.
  127.      */
  128.  
  129.     av = AllocMem(sizeof(char *) * (numac + 3), MEMF_PUBLIC);
  130.     if (!av) {
  131.     *error = (PERR_NOMEM << 16);
  132.     goto fail;
  133.     }
  134.     av += 2;
  135.     av[-2] = (char *)(sizeof(char *) * (numac + 3));
  136.     arglen = AllocMem(sizeof(long) * numac, MEMF_PUBLIC);
  137.     if (!arglen) {
  138.     *error = (PERR_NOMEM << 16);
  139.     goto fail;
  140.     }
  141.  
  142.     {
  143.     register char *ptr;
  144.     register short ac = 0;
  145.     register short quo = 0;
  146.     register short len = 0;
  147.  
  148.     for (ptr = buf; *ptr == ' ' || *ptr == 9; ++ptr);
  149.     for (; *ptr; ++ptr) {
  150.         switch(*ptr) {
  151.         case '(':
  152.         ++quo;
  153.         if (quo != 1)
  154.             ++len;
  155.         break;
  156.         case ')':
  157.         --quo;
  158.         if (quo)
  159.             ++len;
  160.         break;
  161.         case '\\':
  162.         case '^':
  163.         if (ptr[1]) {
  164.             ++ptr;
  165.             ++len;
  166.         }
  167.         break;
  168.         case ' ':
  169.         case 9:
  170.         if (!quo) {
  171.             while (*ptr == ' ' || *ptr == 9)
  172.             ++ptr;
  173.             if (*ptr) {
  174.             arglen[ac] = len;
  175.             ttllen += len + 2;
  176.             ++ac;
  177.             len = 0;
  178.             }
  179.             --ptr;
  180.         } else {
  181.             ++len;
  182.         }
  183.         break;
  184.         case '$':
  185.         {
  186.             register MNODE *node = RemHead(&VList);
  187.             if (node) {
  188.             len += strlen(node+1);
  189.             AddTail(&VList, node);
  190.             }
  191.             ptr = endstrvar(ptr + 1, NULL) - 1;
  192.         }
  193.         break;
  194.         case '\n':
  195.         break;
  196.         default:
  197.         ++len;
  198.         break;
  199.         }
  200.     }
  201.     arglen[ac] = len;
  202.     ttllen += len + 2;        /* 1 byte status & 1 byte separator */
  203.     ++ac;
  204.     }
  205.     {                    /* allocate space for entries */
  206.     register short i;
  207.     register char *mem = AllocMem(4+ttllen, MEMF_PUBLIC);
  208.     register char *ptr = mem + 4;
  209.  
  210.     if (!mem) {
  211.         *error = (PERR_NOMEM << 16);
  212.         goto fail;
  213.     }
  214.  
  215.     *(long *)mem = 4 + ttllen;
  216.     for (i = 0; i < numac; ++i) {
  217.         *ptr++ = 0;         /*  status byte */
  218.         av[i] = ptr;
  219.         ptr[arglen[i]] = 0;
  220.         ptr += arglen[i] + 1;
  221.     }
  222.     av[-1] = mem;
  223.     }
  224.     {
  225.     register char *ptr;
  226.     register char *avs = av[0];
  227.     register short ac = 0;
  228.     short quo = 0;
  229.  
  230.     for (ptr = buf; *ptr == ' ' || *ptr == 9; ++ptr);
  231.     for (; *ptr; ++ptr) {
  232.         switch(*ptr) {
  233.         case '\\':
  234.         if (ptr[1])
  235.             *avs++ = *++ptr;
  236.         break;
  237.         case '^':
  238.         if (ptr[1])
  239.             *avs++ = *++ptr & 0x1F;
  240.         break;
  241.         case '(':
  242.         ++quo;
  243.         if (quo != 1)
  244.             *avs++ = '(';
  245.         else if (avs == av[ac])     /*  quoted argument */
  246.             avs[-1] = 1;
  247.         break;
  248.         case ')':
  249.         --quo;
  250.         if (quo) {
  251.             *avs++ = ')';
  252.             break;
  253.         }   /* fall through */
  254.         case ' ':
  255.         case 9:
  256.         if (!quo) {
  257.             ++ptr;
  258.             while (*ptr == ' ' || *ptr == 9)
  259.             ++ptr;
  260.             if (*ptr) {
  261.             *avs = 0;
  262.             avs = av[++ac];
  263.             }
  264.             --ptr;
  265.         } else {
  266.             *avs++ = *ptr;
  267.         }
  268.         break;
  269.         case '$':
  270.         {
  271.             register MNODE *node = RemHead(&VList);
  272.             if (node) {
  273.             strcpy(avs, node + 1);
  274.             avs += strlen(avs);
  275.             FreeMem(node, 8 + strlen(node+1) + 1);
  276.             }
  277.             ptr = endstrvar(ptr + 1, NULL) - 1;
  278.         }
  279.         break;
  280.         case '\n':
  281.         break;
  282.         default:
  283.         *avs++ = *ptr;
  284.         break;
  285.         }
  286.     }
  287.     *avs = 0;
  288.     ++ac;
  289.     }
  290.     FreeMem(arglen, sizeof(long) * numac);
  291.     *pav = av;
  292.     av[numac] = NULL;
  293.     return(numac);
  294.  
  295. fail:
  296.     {
  297.     register MNODE *node;
  298.  
  299.     if (arglen)
  300.         FreeMem(arglen, sizeof(long) * numac);
  301.     if (av)
  302.         FreeMem(av - 2, (long)av[-2]);
  303.     while (node = RemHead(&VList))
  304.         FreeMem(node, 8 + strlen(node+1) + 1);
  305.     }
  306.     *pav = NULL;
  307.     return(0);
  308. }
  309.  
  310. lFreeParseCmd(av)
  311. char **av;
  312. {
  313.     FreeMem(av[-1], *(long *)av[-1]);
  314.     FreeMem(av - 2, (long)av[-2]);
  315. }
  316.  
  317. char *
  318. endstrvar(ptr, plen)
  319. short *plen;
  320. register char *ptr;
  321. {
  322.     register short len = 0;
  323.     if (*ptr == '(') {
  324.     ++ptr;
  325.     while (*ptr && *ptr != ')') {
  326.         ++ptr;
  327.         ++len;
  328.     }
  329.     if (*ptr == ')')
  330.         ++ptr;
  331.     } else {
  332.     while ((*ptr >= 'a' && *ptr <= 'z') ||
  333.            (*ptr >= 'A' && *ptr <= 'Z') ||
  334.            (*ptr >= '0' && *ptr <= '9') ||
  335.            (*ptr == '_')) {
  336.         ++len;
  337.         ++ptr;
  338.     }
  339.     }
  340.     if (len > 62)
  341.     len = 62;
  342.     if (plen)
  343.     *plen = len;
  344.     return(ptr);
  345. }
  346.  
  347. IPCPORT *
  348. lOpenIPC(name, flags)
  349. char *name;
  350. {
  351.     register IPCPORT *port;
  352.     register char *ptr;
  353.  
  354.     port = AllocMem(sizeof(IPCPORT), MEMF_PUBLIC|MEMF_CLEAR);
  355.     if (!port)
  356.     goto fail;
  357.     ptr = AllocMem(strlen(name)+1, MEMF_PUBLIC);
  358.     if (!ptr)
  359.     goto fail;
  360.     strcpy(ptr, name);
  361.     port->Flags = flags;
  362.     port->Port.mp_Node.ln_Type = NT_MSGPORT;
  363.     port->Port.mp_Node.ln_Name = ptr;
  364.     port->Port.mp_Flags = PA_SIGNAL;
  365.     port->Port.mp_SigBit = AllocSignal(-1);
  366.     port->Port.mp_SigTask = FindTask(NULL);
  367.     NewList(&port->Port.mp_MsgList);
  368.  
  369.     LockAddr(IPCLock);
  370.     Insert(&IPCList, port, FindName(&IPCList, name));
  371.     UnLockAddr(IPCLock);
  372.     return(port);
  373. fail:
  374.     if (port) {
  375.     FreeMem(port, sizeof(IPCPORT));
  376.     if (ptr)
  377.         FreeMem(ptr, strlen(ptr)+1);
  378.     }
  379.     return(NULL);
  380. }
  381.  
  382. void
  383. lCloseIPC(port)
  384. register IPCPORT *port;
  385. {
  386.     register IPCMSG *msg;
  387.  
  388.     LockAddr(IPCLock);              /*  remove port (no new messages)   */
  389.     Remove(port);
  390.     UnLockAddr(IPCLock);
  391.     while (msg = GetMsg(port))      /*  reply to pending msgs w/error   */
  392.     ReplyIPC(msg, NULL, 0, IF_NOTFND);
  393.     FreeMem(port->Port.mp_Node.ln_Name, strlen(port->Port.mp_Node.ln_Name)+1);
  394.     if (port->Port.mp_Flags == PA_SIGNAL)
  395.     FreeSignal(port->Port.mp_SigBit);
  396.     FreeMem(port, sizeof(IPCPORT));
  397. }
  398.  
  399. /*
  400.  *  msg = SendIPC(appname, buf, len, flags)
  401.  */
  402.  
  403. IPCMSG *
  404. lSendIPC(name, buf, len, flags)
  405. char *name;
  406. APTR buf;
  407. register long len, flags;
  408. {
  409.     register IPCMSG *msg;
  410.     register PORT *rport;
  411.  
  412.     msg = AllocMem(sizeof(IPCMSG)+sizeof(PORT), MEMF_PUBLIC|MEMF_CLEAR);
  413.     if (msg == NULL)
  414.     return(NULL);
  415.     flags |= IF_ALLOCMSG;        /*    auto-deallocate later on    */
  416.     rport = (PORT *)(msg + 1);
  417.     if (buf && !(flags & IF_NOCOPY) && !(flags & IF_ALLOC)) {
  418.     if (!(buf = Duplicate(buf, len))) {
  419.         FreeMem(msg, sizeof(IPCMSG)+sizeof(PORT));
  420.         return(NULL);
  421.     }
  422.     flags |= IF_ALLOC;
  423.     }
  424.     rport->mp_Node.ln_Type = NT_MSGPORT;
  425.     rport->mp_Flags = PA_SIGNAL;
  426.     rport->mp_SigBit = 4;
  427.     rport->mp_SigTask = SysBase->ThisTask;
  428.     NewList(&rport->mp_MsgList);
  429.  
  430.     msg->Msg.mn_ReplyPort = rport;
  431.     msg->Msg.mn_Length = sizeof(IPCMSG) + sizeof(PORT);
  432.     msg->TBuf = buf;
  433.     msg->TLen = len;
  434.     msg->TFlags = flags;
  435.     return(lSendIPC2(name, msg));
  436. }
  437.  
  438. IPCMSG *
  439. lSendIPC2(name, msg)
  440. char *name;
  441. register IPCMSG *msg;
  442. {
  443.     register IPCPORT *port;
  444.  
  445.     msg->RBuf = NULL;
  446.     msg->RLen = 0;
  447.     msg->RFlags = 0;
  448.     msg->Error    = 0;
  449.     msg->Confirm = NULL;
  450.  
  451.     LockAddr(IPCLock);
  452.     if (name) {
  453.     port = (IPCPORT *)FindName(&IPCList, name);
  454.     } else {
  455.     port = GetHead(&IPCList);
  456.     }
  457.     msg->ToPort = port;
  458.     if (port) {
  459.     if ((port->Flags & IF_ALLOC) && !(msg->TFlags & IF_ALLOC)) {
  460.         if ((msg->TBuf = Duplicate(msg->TBuf, msg->TLen)) == NULL) {
  461.         msg->Error = PERR_NOMEM;
  462.         lReplyIPC(msg, NULL, 0, IF_ERROR);
  463.         return(msg);
  464.         }
  465.         msg->TFlags |= IF_ALLOC;
  466.     }
  467.     PutMsg(port, msg);
  468.     UnLockAddr(IPCLock);
  469.     } else {
  470.     UnLockAddr(IPCLock);
  471.     lReplyIPC(msg, NULL, 0, IF_ERROR|IF_NOTFND|IF_NOAPP);
  472.     }
  473.     return(msg);
  474. }
  475.  
  476. /*
  477.  *  DoIPC2(name, msg, collfunc, collport)
  478.  *
  479.  *  Synchronous IPC routine.  To prevent lockouts in case the calling task
  480.  *  also owns an IPC port, if this port is provided 'collfunc' will
  481.  *  automatically be called if new requests arrive while we are waiting
  482.  *  for our request to complete.  This call is reentrant.
  483.  */
  484.  
  485. void
  486. lDoIPC2(name, msg, func, port)
  487. char *name;
  488. IPCMSG *msg;
  489. void (*func)();
  490. PORT *port;
  491. {
  492.     SendIPC2(name, msg);        /*  send the message            */
  493.     if (port) {
  494.     register long mask1 = 1 << port->mp_SigBit;
  495.     register long mask2 = 1 << msg->Msg.mn_ReplyPort->mp_SigBit;
  496.  
  497.     while (!CheckMsg(msg)) {
  498.         if (CheckPort(port)) {
  499.         CCall(func, port);
  500.         continue;
  501.         }
  502.         Wait(mask1 | mask2);
  503.     }
  504.     }
  505.     WaitMsg(msg);
  506. }
  507.  
  508. /*
  509.  *  (void )ReplyIPC(msg, buf, len, flags)
  510.  */
  511.  
  512. lReplyIPC(msg, buf, len, flags)
  513. register IPCMSG *msg;
  514. APTR buf;
  515. long len, flags;
  516. {
  517.     if (buf && !(flags & (IF_NOCOPY|IF_ALLOC|IF_NOTFND))) {
  518.     buf = Duplicate(buf, len);
  519.     flags |= IF_ALLOC;
  520.     }
  521.     if (buf || !(flags & IF_NOTFND)) {
  522.     if ((msg->RFlags & IF_ALLOC) && msg->RBuf && buf != msg->RBuf)
  523.         FreeMem(msg->RBuf, msg->RLen);
  524.     msg->RBuf = buf;
  525.     msg->RLen = len;
  526.     }
  527.     msg->RFlags = flags;
  528.     LockAddr(IPCLock);
  529.     if (msg->RFlags & IF_GLOBAL) {
  530.     register IPCPORT *next;
  531.  
  532.     do {
  533.         next = GetSucc(next);
  534.     } while (next && !(next->Flags & IF_GLOBAL));
  535.     if (next) {
  536.         msg->ToPort = next;
  537.         PutMsg(next, msg);
  538.     } else {
  539.         if ((msg->TFlags & IF_ALLOC) && msg->TBuf) {
  540.         FreeMem(msg->TBuf, msg->TLen);
  541.         msg->TBuf = NULL;
  542.         }
  543.         ReplyMsg(msg);
  544.     }
  545.     UnLockAddr(IPCLock);
  546.     return;
  547.     }
  548.     if (flags & IF_NOTFND) {
  549.     register IPCPORT *next = GetSucc(msg->ToPort);
  550.     if (next && strcmp(msg->ToPort->Port.mp_Node.ln_Name, next->Port.mp_Node.ln_Name) == 0) {
  551.         msg->ToPort = next;
  552.         PutMsg(next, msg);
  553.     } else {
  554.         if ((msg->TFlags & IF_ALLOC) && msg->TBuf) {
  555.         FreeMem(msg->TBuf, msg->TLen);
  556.         msg->TBuf = NULL;
  557.         }
  558.         ReplyMsg(msg);
  559.         msg->RFlags |= IF_ERROR;
  560.     }
  561.     UnLockAddr(IPCLock);
  562.     return;
  563.     }
  564.     UnLockAddr(IPCLock);
  565.     if ((msg->TFlags & IF_ALLOC) && msg->TBuf) {
  566.     FreeMem(msg->TBuf, msg->TLen);
  567.     msg->TBuf = NULL;
  568.     }
  569.     ReplyMsg(msg);
  570.     return;
  571. }
  572.  
  573. /*
  574.  * (void) lFreeIPC(msg)
  575.  *
  576.  *  Free space associated with the reply buffer and possibly the message
  577.  *  itself.  This call MUST be made after you receive a reply to your
  578.  *  message.
  579.  */
  580.  
  581. void
  582. lFreeIPC(msg)
  583. register IPCMSG *msg;
  584. {
  585.     if ((msg->RFlags & IF_ALLOC) && msg->RBuf) {
  586.     FreeMem(msg->RBuf, msg->RLen);
  587.     msg->RBuf = NULL;
  588.     }
  589.     if (msg->Confirm)                   /*  Confirmation requested  */
  590.     CCall(msg->Confirm, msg);
  591.     if (msg->TFlags & IF_ALLOCMSG)      /*  Message was allocated   */
  592.     FreeMem(msg, msg->Msg.mn_Length);
  593. }
  594.  
  595. APTR
  596. Duplicate(buf, len)
  597. APTR buf;
  598. long len;
  599. {
  600.     APTR newbuf;
  601.     if (newbuf = AllocMem(len, TypeOfMem(buf))) {
  602.     BMov(buf, newbuf, len);
  603.     return(newbuf);
  604.     }
  605.     return(NULL);
  606. }
  607.  
  608. #asm
  609.  
  610.         ;    CCall(funcptr, argument)
  611.  
  612. _CCall:     movem.l 4(sp),A0/A1
  613.         movem.l D2/D3/A4/A5/A6,-(sp)
  614.         move.l  A1,-(sp)
  615.         jsr     (A0)
  616.         addq.l  #4,sp
  617.         movem.l (sp)+,D2/D3/A4/A5/A6
  618.         rts
  619. #endasm
  620.  
  621.