home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 626a.lha / GUISpell_v1.0 / GUISpell.c < prev    next >
C/C++ Source or Header  |  1992-03-27  |  16KB  |  561 lines

  1. #error By license, you aren't permitted to compile this.  Read GUISpell.doc.
  2. #error You may obtain a license from the author,
  3. #error Loren J. Rittle (l-rittle@uiuc.edu).  Again, read GUISpell.doc.
  4. #include <string.h>
  5. #include <devices/clipboard.h>
  6. #include <proto/all.h>
  7. #include "libraries.h"
  8. #include "error.h"
  9. #include "minrexx.h"
  10. #include "textclip.h"
  11.  
  12. extern long __builtin_getreg (int);
  13. extern void __builtin_putreg (int, long);
  14. #define REG_A4 12
  15.  
  16. extern char *_ProgramName;
  17.  
  18. #define VERSION "GUISpell 1.0 (26.3.92)"
  19. #define NICE_VERSION "GUISpell-1.0 (" __DATE__ " " __TIME__ ")"
  20.  
  21. static char Version_ID[] = "$VER: " VERSION;
  22.  
  23. char *listText[512];
  24. char *initListText[] =
  25. {
  26.   NICE_VERSION,
  27.   "This is a freely distributable version",
  28.   "Copyright \xa9 1991, 1992  Loren J. Rittle",
  29.   "",
  30.   "GUISpell is the premier GUI front-end",
  31.   "to ISpell 3.1ljr (or later) with ARexx",
  32.   "Server Mode, for AmigaOS Release 2.04.",
  33.   "",
  34.   "If you use this software, please mail",
  35.   "the author at l-rittle@uiuc.edu, so I",
  36.   "can inform you of bugs and upgrades.",
  37.   0,
  38. };
  39.  
  40. struct List lvList;
  41. struct Gadget *gList;
  42. struct Window *window;
  43. struct Screen *screen;
  44. struct VisualInfo *vi;
  45. void *memory;
  46. struct IOClipReq *ClipReq;
  47. struct MsgPort *ClipPort;
  48. struct Hook ClipHook;
  49. struct ClipHookMsg ClipHookMsg = {0, CMD_UPDATE, 0};
  50. struct Task *Task;
  51. ULONG ClipAlertSignalNum = -1;
  52. BOOL done;
  53. int auto_clip;
  54. int lookup_type;
  55.  
  56. struct TextAttr topaz80 = {"topaz.font", 8, 0, 0};
  57.  
  58. char *cycleText[] = {"Spell", "Reg exp", "Exact", 0};
  59.  
  60. struct TagItem nullTags[] = {TAG_DONE, 0};
  61. struct TagItem cycleTags[] = {GTCY_Labels, &cycleText[0], GTBB_Recessed, FALSE, TAG_DONE, 0};
  62. struct TagItem listviewTags[] = {GTLV_Labels, &lvList, GTLV_ReadOnly, FALSE, GTLV_ScrollWidth, 16, TAG_DONE, 0};
  63. struct TagItem stringTags[] = {GTTX_CopyText, TRUE, GTTX_Border, FALSE, TAG_DONE, 0};
  64.  
  65. struct
  66. {
  67.   struct TagItem *tags;
  68.   ULONG kind;
  69.   UWORD left, top, width, height;
  70.   ULONG flags;
  71.   char *text;
  72.   struct Gadget *object;
  73. } gads[] =
  74. {
  75.   {cycleTags, CYCLE_KIND, 121, 13, 90, 12, NG_HIGHLABEL, "Lookup Style:", 0},
  76.   {nullTags, CHECKBOX_KIND, 310, 13, 80, 12, NG_HIGHLABEL, "Auto-Clip:", 0},
  77.   {listviewTags, LISTVIEW_KIND, 20, 44, 360, 92, NG_HIGHLABEL | PLACETEXT_ABOVE, "", 0},
  78.   {nullTags, BUTTON_KIND, 234, 27, 81, 12, NG_HIGHLABEL | PLACETEXT_IN,"From Clip", 0},
  79.   {nullTags, BUTTON_KIND, 325, 27, 65, 12, NG_HIGHLABEL | PLACETEXT_IN,"To Clip", 0},
  80.   {nullTags, BUTTON_KIND, 350, 13, 40, 12, NG_HIGHLABEL | PLACETEXT_IN,"Add", 0},
  81.   {stringTags, STRING_KIND, 10, 27, 180, 12, NG_HIGHLABEL, "", 0},
  82.   {nullTags, BUTTON_KIND, 200, 27, 24, 12, NG_HIGHLABEL | PLACETEXT_IN,"Do", 0},
  83.   {0, 0, 0, 0, 0, 0, 0, 0, 0},
  84. };
  85.  
  86. #define    LOOKUP_STYLE_ID    0
  87. #define    AUTO_CLIP_ID    1
  88. #define    WORD_LIST_ID    2
  89. #define FROM_CLIP_ID    3
  90. #define TO_CLIP_ID    4
  91. #define ADD_WORD_ID    5
  92. #define USER_WORD_ID    6
  93. #define DO_ID        7
  94.  
  95. int main (int argc, char *argv[]);
  96. void SubmitCheckRequest (int type, char *word);
  97. void UpdateList (struct RexxMsg *msg);
  98. void ProcessGadget (UWORD id, UWORD code);
  99. void GadgetUp (struct IntuiMessage *m);
  100. void *CreateList (struct List *list, char *array[]);
  101. struct Gadget *CreateGadgets (void);
  102. void OpenAll (void);
  103. void CloseAll (void);
  104. void rexxdisp (struct RexxMsg *msg, struct rexxCommandList *dat, char *p);
  105.  
  106. void rexxcheck (struct RexxMsg *msg, char *p);
  107. //void rexxquickcheck (struct RexxMsg *msg, char *p);
  108. //void rexxlookup (struct RexxMsg *msg, char *p);
  109. //void rexxcheckmode (struct RexxMsg *msg, char *p);
  110. //void rexxautomode (struct RexxMsg *msg, char *p);
  111. //void rexxzoommode (struct RexxMsg *msg, char *p);
  112. //void rexxzoomwindow (struct RexxMsg *msg, char *p);
  113. void rexxcurrenttext (struct RexxMsg *msg, char *p);
  114. void rexxcheckcallbackhook (struct RexxMsg *msg, char *p);
  115. void invokerexxcheckcallbackhook (void);
  116. void rexxversion (struct RexxMsg *msg, char *p);
  117. void rexxexit (struct RexxMsg *msg, char *p);
  118.  
  119. struct rexxCommandList rcl[] =
  120. {
  121.   {"check", &rexxcheck},
  122.   {"currenttext", &rexxcurrenttext},
  123.   {"checkcallbackhook", &rexxcheckcallbackhook},
  124.   {"version", &rexxversion},
  125.   {"exit", &rexxexit},
  126.   {NULL, NULL}
  127. };
  128.  
  129. /* This is really kludged up to get it to work under SAS/C 5.10b
  130.    with cres.o.  This code is unportable between compilers and
  131.    in fact may fail with other versions of SAS/C.  */
  132. ULONG __asm ClipChange (register __a0 struct Hook *hook,
  133.             register __a4 void *junk)
  134. {
  135.   __builtin_putreg (REG_A4, (long) hook->h_SubEntry);
  136.   Signal (Task, 1 << ClipAlertSignalNum);
  137.   return 0;
  138. }
  139.  
  140. int main (int argc, char *argv[])
  141. {
  142.   long rexxbit;
  143.  
  144.   OnError (&CloseAll);
  145.  
  146.   {
  147.     int i;
  148.  
  149.     for (i = 0; initListText[i]; i++)
  150.       listText[i] = initListText[i];
  151.   }
  152.  
  153.   OpenAll ();
  154.  
  155.   if (!(rexxbit = upRexxPort ("GUISpell", rcl, 0, &rexxdisp)))
  156.     Error ("ss", _ProgramName, ": MinRexx had a problem.\n");
  157.  
  158.   while (!done)
  159.     {
  160.       struct IntuiMessage *m;
  161.       long returnbits = Wait ((1 << window->UserPort->mp_SigBit) | rexxbit |
  162.                   (1 << ClipAlertSignalNum) | SIGBREAKF_CTRL_C);
  163.  
  164.       if (returnbits & SIGBREAKF_CTRL_C)
  165.     done = 1;
  166.       if (returnbits & rexxbit)
  167.     dispRexxPort ();
  168.       if ((returnbits & (1 << ClipAlertSignalNum)) && auto_clip)
  169.     {
  170.           char buffer[256];
  171.  
  172.           if (TextFromClip (buffer, 256) && !strchr (buffer, ' '))
  173.         {
  174.           static struct TagItem tags[] = {GTST_String, 0, TAG_DONE, 0};
  175.  
  176.           tags[0].ti_Data = (ULONG) buffer;
  177.           GT_SetGadgetAttrsA(gads[USER_WORD_ID].object, window, NULL, tags);
  178.           SubmitCheckRequest (lookup_type, ((struct StringInfo *)gads[USER_WORD_ID].object->SpecialInfo)->Buffer);
  179.         }
  180.     }
  181.       if (returnbits & (1 << window->UserPort->mp_SigBit))
  182.         while (m = GT_GetIMsg (window->UserPort))
  183.       {
  184.         struct IntuiMessage msg = *m;
  185.         GT_ReplyIMsg (m);
  186.  
  187.         switch (msg.Class)
  188.           {
  189.           case IDCMP_GADGETUP:
  190.         if (msg.Code == 0x09)
  191.           {
  192.           }
  193.         if (msg.Code == 0x5f)
  194.           {
  195.           }
  196.         else
  197.           ProcessGadget (((struct Gadget *) msg.IAddress)->GadgetID, msg.Code);
  198.             break;
  199.  
  200.           case IDCMP_REFRESHWINDOW:
  201.             GT_BeginRefresh (window);
  202.             GT_EndRefresh (window, TRUE);
  203.             break;
  204.  
  205.           case IDCMP_CLOSEWINDOW:
  206.             done = 1;
  207.             break;
  208.  
  209.           default:
  210.             break;
  211.           }
  212.       }
  213.     }
  214.  
  215.   CloseAll ();
  216.   return 0;
  217. }
  218.  
  219. void SubmitCheckRequest (int lookup_type, char *word)
  220. {
  221.   char buffer[256];
  222.   static char *rexxcommandname[] = {"check ", "lookup ", "quickcheck ", "add "};
  223.  
  224.   if (lookup_type > 3)
  225.     {
  226.       DisplayBeep (0);
  227.       return;
  228.     }
  229.   strcpy (buffer, rexxcommandname[lookup_type]);
  230.   strncat (buffer, word, 240);
  231.   if (!sendSimpleCmd (buffer, "IRexxSpell", &UpdateList, NULL, NULL, NULL))
  232.     DisplayBeep (0);
  233. }
  234.  
  235. void UpdateList (struct RexxMsg *msg)
  236. {
  237.   static struct TagItem tags[] = {GTLV_Labels, ~0, TAG_DONE, 0};
  238.   static struct TagItem tags2[] = {GTLV_Labels, &lvList, GTLV_Top, 0, TAG_DONE, 0};
  239.   static char buffer[513];
  240.  
  241.   if (!msg->rm_Result1 && msg->rm_Result2)
  242.     {
  243.       GT_SetGadgetAttrsA (gads[WORD_LIST_ID].object, window, NULL, tags);
  244.  
  245.       if (((struct RexxArg *) (msg->rm_Result2-8))->ra_Length > 512)
  246.     {
  247.           memcpy (buffer, (char *) msg->rm_Result2, 512);
  248.       buffer[512] = '\0';
  249.     }
  250.       else
  251.     {
  252.           memcpy (buffer, (char *) msg->rm_Result2,
  253.           ((struct RexxArg *) (msg->rm_Result2-8))->ra_Length);
  254.           buffer[((struct RexxArg *) (msg->rm_Result2-8))->ra_Length] = '\0';
  255.     }
  256.  
  257.       {
  258.     int a, b = 0;
  259.  
  260.     listText[b++] = &buffer[0];
  261.     for (a = 0; buffer[a]; a++)
  262.       if (buffer[a] == ' ')
  263.         {
  264.           if (buffer[a+1])
  265.         listText[b++] = &buffer[a+1];
  266.           buffer[a] = '\0';
  267.         }
  268.     listText[b] = 0;
  269.       }
  270.       
  271.       if (memory)
  272.         {
  273.           FreeVec (memory);
  274.           memory = 0;
  275.         }
  276.       memory = CreateList (&lvList, &listText[0]);
  277.  
  278.       GT_SetGadgetAttrsA (gads[WORD_LIST_ID].object, window, NULL, tags2);
  279.  
  280.       DeleteArgstring ((char *) msg->rm_Result2);
  281.     }
  282.   else
  283.     DisplayBeep (0);
  284. }
  285.  
  286. void ProcessGadget (UWORD id, UWORD code)
  287. {
  288.   switch (id)
  289.     {
  290.     case LOOKUP_STYLE_ID:
  291.       lookup_type = code;
  292.       break;
  293.     case AUTO_CLIP_ID:
  294.       auto_clip = gads[id].object->Flags & SELECTED;
  295.       break;
  296.     case WORD_LIST_ID:
  297.      {
  298.       static struct TagItem tags[] = {GTST_String, 0, TAG_DONE, 0};
  299.       tags[0].ti_Data = (ULONG) listText[code];
  300.       GT_SetGadgetAttrsA(gads[USER_WORD_ID].object, window, NULL, tags);
  301.       if (auto_clip)
  302.     TextToClip (((struct StringInfo *)gads[USER_WORD_ID].object->SpecialInfo)->Buffer);
  303.       invokerexxcheckcallbackhook ();
  304.       break;
  305.      }
  306.     case FROM_CLIP_ID:
  307.      {
  308.       char buffer[256];
  309.  
  310.       if (TextFromClip (buffer, 256))
  311.     {
  312.       static struct TagItem tags[] = {GTST_String, 0, TAG_DONE, 0};
  313.  
  314.       tags[0].ti_Data = (ULONG) buffer;
  315.       GT_SetGadgetAttrsA(gads[USER_WORD_ID].object, window, NULL, tags);
  316.       if (!strchr (buffer, ' '))
  317.         SubmitCheckRequest (lookup_type, ((struct StringInfo *)gads[USER_WORD_ID].object->SpecialInfo)->Buffer);
  318.     }
  319.       break;
  320.      }
  321.     case TO_CLIP_ID:
  322.       TextToClip (((struct StringInfo *)gads[USER_WORD_ID].object->SpecialInfo)->Buffer);
  323.       break;
  324.     case ADD_WORD_ID:
  325.       SubmitCheckRequest (3, ((struct StringInfo *)gads[USER_WORD_ID].object->SpecialInfo)->Buffer);
  326.       break;
  327.     case DO_ID:
  328.     case USER_WORD_ID:
  329.       SubmitCheckRequest (lookup_type, ((struct StringInfo *)gads[USER_WORD_ID].object->SpecialInfo)->Buffer);
  330.       break;
  331.     default:
  332.       break;
  333.     }
  334. }
  335.  
  336. void *CreateList (struct List *list, char *array[])
  337. {
  338.   short i;
  339.   struct Node *np, *start_np;
  340.  
  341.   NewList (list);
  342.   for (i = 0; array[i]; i++)
  343.     ;
  344.   start_np = AllocVec (sizeof (struct Node) * i, 0);
  345.   if (!start_np)
  346.     Error ("ss", _ProgramName, ": No free memory!\n");
  347.  
  348.   for (i = 0, np = start_np; array[i]; i++, np++)
  349.     {
  350.       np->ln_Name = (APTR) array[i];
  351.       np->ln_Pri = 0;
  352.       AddTail (list, np);
  353.     }
  354.   return start_np;
  355. }
  356.  
  357. struct Gadget *CreateGadgets (void)
  358. {
  359.   struct Gadget *gadget, *glist = 0;
  360.   short i;
  361.   struct NewGadget ng;
  362.  
  363.   gadget = CreateContext (&glist);
  364.   if (!gadget)
  365.     Error ("ss", _ProgramName, ": Can't CreateContext\n");
  366.   for (i = 0; gads[i].tags; i++)
  367.     {
  368.       ng.ng_GadgetID = i;
  369.       ng.ng_TextAttr = &topaz80;
  370.       ng.ng_VisualInfo = vi;
  371.       ng.ng_LeftEdge = gads[i].left;
  372.       ng.ng_TopEdge = gads[i].top;
  373.       ng.ng_Width = gads[i].width;
  374.       ng.ng_Height = gads[i].height;
  375.       ng.ng_GadgetText = gads[i].text;
  376.       ng.ng_Flags = gads[i].flags;
  377.       gads[i].object = gadget = CreateGadgetA (gads[i].kind, gadget, &ng, gads[i].tags);
  378.       if (!gadget)
  379.     Error ("ss", _ProgramName, ": Can't CreateGadget\n");
  380.     }
  381.   return glist;
  382. }
  383.  
  384. void OpenAll (void)
  385. {
  386.   static struct TagItem tags[] = {GTLV_Labels, ~0, TAG_DONE, 0};
  387.   static WORD zoom_data[4] = {0, 0, 400, 43};
  388.   static struct TagItem wtags[] =
  389.     {
  390.       WA_Left, 0, WA_Top, 0, WA_Width, 400, WA_Height, 143,
  391.       WA_MinWidth, 400, WA_MinHeight, 43, WA_MaxWidth, -1, WA_MaxHeight, -1,
  392.       WA_DetailPen, 0, WA_BlockPen, 3, WA_IDCMP, 
  393.       IDCMP_REFRESHWINDOW|IDCMP_CLOSEWINDOW|BUTTONIDCMP|CYCLEIDCMP|LISTVIEWIDCMP,
  394.       WA_Gadgets, 0 /*set below*/, WA_PubScreen, 0, /*set below*/
  395.       WA_Title, (ULONG)"GUISpell-1.0", WA_SuperBitMap, 0,
  396.       WA_SizeGadget, FALSE, WA_DragBar, TRUE, WA_DepthGadget, TRUE,
  397.       WA_CloseGadget, TRUE, WA_Backdrop, FALSE, WA_ReportMouse, FALSE,
  398.       WA_Borderless, FALSE, WA_Activate, TRUE, WA_RMBTrap, FALSE,
  399.       WA_SimpleRefresh, TRUE, WA_Zoom, (ULONG)zoom_data, WA_RMBTrap, TRUE, TAG_DONE, 0
  400.     };
  401.  
  402.   OpenLibraries ();
  403.  
  404.   screen = LockPubScreen ("CygnusEdScreen1");
  405.   if (!screen)
  406.     screen = LockPubScreen ("Workbench");
  407.   if (!screen)
  408.     Error ("ss", _ProgramName, ": Can't Lock WB Screen!\n");
  409.  
  410.   vi = GetVisualInfoA (screen, TAG_DONE);
  411.   if (!vi)
  412.     Error ("ss", _ProgramName, ": Can't GetVisualInfoA\n");
  413.  
  414.   memory = CreateList (&lvList, &listText[0]);
  415.   gList = CreateGadgets ();
  416.   wtags[11].ti_Data = (ULONG) gList;
  417.   wtags[12].ti_Data = (ULONG) screen;
  418.   window = OpenWindowTagList (NULL, wtags);
  419.   UnlockPubScreen (0, screen);
  420.   if (!window)
  421.     Error ("ss", _ProgramName, ": Can't open window\n");
  422.   GT_RefreshWindow (window, NULL);
  423.   GT_SetGadgetAttrsA (gads[WORD_LIST_ID].object, window, NULL, tags);
  424.  
  425.   Task = FindTask (0);
  426.   if ((ClipAlertSignalNum = AllocSignal (-1)) == -1)
  427.     Error ("ss", _ProgramName, ": Can't get a signal\n");
  428.   if (!(ClipPort = CreatePort (0L, 0L)))
  429.     Error ("ss", _ProgramName, ": Can't create port\n");
  430.   if (!(ClipReq = (struct IOClipReq *) CreateExtIO (ClipPort, sizeof (*ClipReq))))
  431.     Error ("ss", _ProgramName, ": Can't create ExtIO\n");
  432.   if (OpenDevice ("clipboard.device", 0L, (struct IORequest *) ClipReq, 0L))
  433.     Error ("ss", _ProgramName, ": Can't open clipboard device\n");
  434.   ClipReq->io_Command = CBD_CHANGEHOOK;
  435.   ClipReq->io_Length = 1;
  436.   ClipReq->io_Data = (void *) &ClipHook;
  437.   ClipHook.h_Entry = (void *) &ClipChange;
  438.   ClipHook.h_SubEntry = (void *) __builtin_getreg (REG_A4);
  439.   ClipHook.h_Data = &ClipHookMsg;
  440.   if (DoIO ((struct IORequest *) ClipReq))
  441.     Error ("ss", _ProgramName, ": Can't install clipboard hook\n");
  442. }
  443.  
  444. void CloseAll (void)
  445. {
  446.   struct IntuiMessage *msg;
  447.  
  448.   if (ClipReq)
  449.     {
  450.       ClipReq->io_Command = CBD_CHANGEHOOK;
  451.       ClipReq->io_Length = 0;
  452.       ClipReq->io_Data = (void *) &ClipHook;
  453.       if (DoIO ((struct IORequest *) ClipReq))
  454.         Warning ("ss", _ProgramName, ": Can't deinstall clipboard hook (crash soon... :-)\n");
  455.       if (ClipReq->io_Device)
  456.         CloseDevice ((struct IORequest *)ClipReq);
  457.       DeleteExtIO ((struct IORequest *)ClipReq);
  458.     }
  459.   if (ClipPort)
  460.     DeletePort (ClipPort);
  461.   if (ClipAlertSignalNum != -1)
  462.     FreeSignal (ClipAlertSignalNum);
  463.  
  464.   dnRexxPort ();
  465.  
  466.   if (window)
  467.     {
  468.       while (msg = (struct IntuiMessage *) GT_GetIMsg (window->UserPort))
  469.     GT_ReplyIMsg (msg);
  470.       CloseWindow (window);
  471.       window = 0;
  472.     }
  473.  
  474.   if (vi)
  475.     {
  476.       FreeVisualInfo (vi);
  477.       vi = 0;
  478.     }
  479.  
  480.   if (gList)
  481.     {
  482.       FreeGadgets (gList);
  483.       gList = 0;
  484.     }
  485.  
  486.   if (memory)
  487.     {
  488.       FreeVec (memory);
  489.       memory = 0;
  490.     }
  491.  
  492.   CloseLibraries ();
  493. }
  494.  
  495. void rexxdisp (struct RexxMsg *msg, struct rexxCommandList *dat, char *p)
  496. {
  497.   dat->userdata(msg, p);
  498. }
  499.  
  500. void rexxcheck (struct RexxMsg *msg, char *p)
  501. {
  502.   static struct TagItem tags[] = {GTST_String, 0, TAG_DONE, 0};
  503.  
  504.   tags[0].ti_Data = (ULONG) p;
  505.   GT_SetGadgetAttrsA(gads[USER_WORD_ID].object, window, NULL, tags);
  506.   SubmitCheckRequest (0, ((struct StringInfo *)gads[USER_WORD_ID].object->SpecialInfo)->Buffer);
  507.   replyRexxCmd (msg, 0L, 0L, "ok");
  508. }
  509.  
  510. void rexxcurrenttext (struct RexxMsg *msg, char *p)
  511. {
  512.   replyRexxCmd (msg, 0L, 0L, ((struct StringInfo *)gads[USER_WORD_ID].object->SpecialInfo)->Buffer);
  513. }
  514.  
  515. char checkcallbackhookcode[512];
  516.  
  517. void rexxcheckcallbackhook (struct RexxMsg *msg, char *p)
  518. {
  519.   if (!checkcallbackhookcode[0] || (strlen (p) < sizeof (checkcallbackhookcode)))
  520.     {
  521.       strcpy (checkcallbackhookcode, p);
  522.       replyRexxCmd (msg, 0L, 0L, "installed");
  523.     }
  524.   else
  525.     replyRexxCmd (msg, 0L, 0L, "notinstalled");
  526. }
  527.  
  528. void invokerexxcheckcallbackhook (void)
  529. {
  530.   if (checkcallbackhookcode[0] && !asyncRexxCmd (checkcallbackhookcode))
  531.     DisplayBeep (0);
  532.   checkcallbackhookcode[0] = '\0';
  533. }
  534.  
  535. void rexxversion (struct RexxMsg *msg, char *p)
  536. {
  537.   char buf[512];
  538.   int bufend = strlen(Version_ID+6);
  539.   int namesize;
  540.   int i;
  541.  
  542.   strcpy(buf, Version_ID+6);
  543.   buf[bufend++] = '\n';
  544.   for (i = 0; rcl[i].name != NULL; i++)
  545.     {
  546.       namesize = strlen(rcl[i].name);
  547.       if ((namesize + bufend) > 511)
  548.     break;
  549.       strcpy (&(buf[bufend++]), " ");
  550.       strcpy (&(buf[bufend]), rcl[i].name);
  551.       bufend += namesize;
  552.     }
  553.   replyRexxCmd (msg, 0L, 0L, buf);
  554. }
  555.  
  556. void rexxexit (struct RexxMsg *msg, char *p)
  557. {
  558.   done = 1;
  559.   replyRexxCmd (msg, 0L, 0L, "bye");
  560. }
  561.